~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/net/ynl/ynl-gen-c.py

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /tools/net/ynl/ynl-gen-c.py (Version linux-6.12-rc7) and /tools/net/ynl/ynl-gen-c.py (Version linux-6.8.12)


  1 #!/usr/bin/env python3                              1 #!/usr/bin/env python3
  2 # SPDX-License-Identifier: ((GPL-2.0 WITH Linu      2 # SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
  3                                                     3 
  4 import argparse                                     4 import argparse
  5 import collections                                  5 import collections
  6 import filecmp                                      6 import filecmp
  7 import os                                           7 import os
  8 import re                                           8 import re
  9 import shutil                                       9 import shutil
 10 import tempfile                                    10 import tempfile
 11 import yaml                                        11 import yaml
 12                                                    12 
 13 from lib import SpecFamily, SpecAttrSet, SpecA     13 from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry
 14                                                    14 
 15                                                    15 
 16 def c_upper(name):                                 16 def c_upper(name):
 17     return name.upper().replace('-', '_')          17     return name.upper().replace('-', '_')
 18                                                    18 
 19                                                    19 
 20 def c_lower(name):                                 20 def c_lower(name):
 21     return name.lower().replace('-', '_')          21     return name.lower().replace('-', '_')
 22                                                    22 
 23                                                    23 
 24 def limit_to_number(name):                         24 def limit_to_number(name):
 25     """                                            25     """
 26     Turn a string limit like u32-max or s64-mi     26     Turn a string limit like u32-max or s64-min into its numerical value
 27     """                                            27     """
 28     if name[0] == 'u' and name.endswith('-min'     28     if name[0] == 'u' and name.endswith('-min'):
 29         return 0                                   29         return 0
 30     width = int(name[1:-4])                        30     width = int(name[1:-4])
 31     if name[0] == 's':                             31     if name[0] == 's':
 32         width -= 1                                 32         width -= 1
 33     value = (1 << width) - 1                       33     value = (1 << width) - 1
 34     if name[0] == 's' and name.endswith('-min'     34     if name[0] == 's' and name.endswith('-min'):
 35         value = -value - 1                         35         value = -value - 1
 36     return value                                   36     return value
 37                                                    37 
 38                                                    38 
 39 class BaseNlLib:                                   39 class BaseNlLib:
 40     def get_family_id(self):                       40     def get_family_id(self):
 41         return 'ys->family_id'                     41         return 'ys->family_id'
 42                                                    42 
                                                   >>  43     def parse_cb_run(self, cb, data, is_dump=False, indent=1):
                                                   >>  44         ind = '\n\t\t' + '\t' * indent + ' '
                                                   >>  45         if is_dump:
                                                   >>  46             return f"mnl_cb_run2(ys->rx_buf, len, 0, 0, {cb}, {data},{ind}ynl_cb_array, NLMSG_MIN_TYPE)"
                                                   >>  47         else:
                                                   >>  48             return f"mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,{ind}{cb}, {data},{ind}" + \
                                                   >>  49                    "ynl_cb_array, NLMSG_MIN_TYPE)"
                                                   >>  50 
 43                                                    51 
 44 class Type(SpecAttr):                              52 class Type(SpecAttr):
 45     def __init__(self, family, attr_set, attr,     53     def __init__(self, family, attr_set, attr, value):
 46         super().__init__(family, attr_set, att     54         super().__init__(family, attr_set, attr, value)
 47                                                    55 
 48         self.attr = attr                           56         self.attr = attr
 49         self.attr_set = attr_set                   57         self.attr_set = attr_set
 50         self.type = attr['type']                   58         self.type = attr['type']
 51         self.checks = attr.get('checks', {})       59         self.checks = attr.get('checks', {})
 52                                                    60 
 53         self.request = False                       61         self.request = False
 54         self.reply = False                         62         self.reply = False
 55                                                    63 
 56         if 'len' in attr:                          64         if 'len' in attr:
 57             self.len = attr['len']                 65             self.len = attr['len']
 58                                                    66 
 59         if 'nested-attributes' in attr:            67         if 'nested-attributes' in attr:
 60             self.nested_attrs = attr['nested-a     68             self.nested_attrs = attr['nested-attributes']
 61             if self.nested_attrs == family.nam     69             if self.nested_attrs == family.name:
 62                 self.nested_render_name = c_lo !!  70                 self.nested_render_name = c_lower(f"{family.name}")
 63             else:                                  71             else:
 64                 self.nested_render_name = c_lo !!  72                 self.nested_render_name = c_lower(f"{family.name}_{self.nested_attrs}")
 65                                                    73 
 66             if self.nested_attrs in self.famil     74             if self.nested_attrs in self.family.consts:
 67                 self.nested_struct_type = 'str     75                 self.nested_struct_type = 'struct ' + self.nested_render_name + '_'
 68             else:                                  76             else:
 69                 self.nested_struct_type = 'str     77                 self.nested_struct_type = 'struct ' + self.nested_render_name
 70                                                    78 
 71         self.c_name = c_lower(self.name)           79         self.c_name = c_lower(self.name)
 72         if self.c_name in _C_KW:                   80         if self.c_name in _C_KW:
 73             self.c_name += '_'                     81             self.c_name += '_'
 74                                                    82 
 75         # Added by resolve():                      83         # Added by resolve():
 76         self.enum_name = None                      84         self.enum_name = None
 77         delattr(self, "enum_name")                 85         delattr(self, "enum_name")
 78                                                    86 
 79     def get_limit(self, limit, default=None):      87     def get_limit(self, limit, default=None):
 80         value = self.checks.get(limit, default     88         value = self.checks.get(limit, default)
 81         if value is None:                          89         if value is None:
 82             return value                           90             return value
 83         elif value in self.family.consts:      << 
 84             return c_upper(f"{self.family['nam << 
 85         if not isinstance(value, int):             91         if not isinstance(value, int):
 86             value = limit_to_number(value)         92             value = limit_to_number(value)
 87         return value                               93         return value
 88                                                    94 
 89     def resolve(self):                             95     def resolve(self):
 90         if 'name-prefix' in self.attr:             96         if 'name-prefix' in self.attr:
 91             enum_name = f"{self.attr['name-pre     97             enum_name = f"{self.attr['name-prefix']}{self.name}"
 92         else:                                      98         else:
 93             enum_name = f"{self.attr_set.name_     99             enum_name = f"{self.attr_set.name_prefix}{self.name}"
 94         self.enum_name = c_upper(enum_name)       100         self.enum_name = c_upper(enum_name)
 95                                                   101 
 96     def is_multi_val(self):                       102     def is_multi_val(self):
 97         return None                               103         return None
 98                                                   104 
 99     def is_scalar(self):                          105     def is_scalar(self):
100         return self.type in {'u8', 'u16', 'u32    106         return self.type in {'u8', 'u16', 'u32', 'u64', 's32', 's64'}
101                                                   107 
102     def is_recursive(self):                       108     def is_recursive(self):
103         return False                              109         return False
104                                                   110 
105     def is_recursive_for_op(self, ri):            111     def is_recursive_for_op(self, ri):
106         return self.is_recursive() and not ri.    112         return self.is_recursive() and not ri.op
107                                                   113 
108     def presence_type(self):                      114     def presence_type(self):
109         return 'bit'                              115         return 'bit'
110                                                   116 
111     def presence_member(self, space, type_filt    117     def presence_member(self, space, type_filter):
112         if self.presence_type() != type_filter    118         if self.presence_type() != type_filter:
113             return                                119             return
114                                                   120 
115         if self.presence_type() == 'bit':         121         if self.presence_type() == 'bit':
116             pfx = '__' if space == 'user' else    122             pfx = '__' if space == 'user' else ''
117             return f"{pfx}u32 {self.c_name}:1;    123             return f"{pfx}u32 {self.c_name}:1;"
118                                                   124 
119         if self.presence_type() == 'len':         125         if self.presence_type() == 'len':
120             pfx = '__' if space == 'user' else    126             pfx = '__' if space == 'user' else ''
121             return f"{pfx}u32 {self.c_name}_le    127             return f"{pfx}u32 {self.c_name}_len;"
122                                                   128 
123     def _complex_member_type(self, ri):           129     def _complex_member_type(self, ri):
124         return None                               130         return None
125                                                   131 
126     def free_needs_iter(self):                    132     def free_needs_iter(self):
127         return False                              133         return False
128                                                   134 
129     def free(self, ri, var, ref):                 135     def free(self, ri, var, ref):
130         if self.is_multi_val() or self.presenc    136         if self.is_multi_val() or self.presence_type() == 'len':
131             ri.cw.p(f'free({var}->{ref}{self.c    137             ri.cw.p(f'free({var}->{ref}{self.c_name});')
132                                                   138 
133     def arg_member(self, ri):                     139     def arg_member(self, ri):
134         member = self._complex_member_type(ri)    140         member = self._complex_member_type(ri)
135         if member:                                141         if member:
136             arg = [member + ' *' + self.c_name    142             arg = [member + ' *' + self.c_name]
137             if self.presence_type() == 'count'    143             if self.presence_type() == 'count':
138                 arg += ['unsigned int n_' + se    144                 arg += ['unsigned int n_' + self.c_name]
139             return arg                            145             return arg
140         raise Exception(f"Struct member not im    146         raise Exception(f"Struct member not implemented for class type {self.type}")
141                                                   147 
142     def struct_member(self, ri):                  148     def struct_member(self, ri):
143         if self.is_multi_val():                   149         if self.is_multi_val():
144             ri.cw.p(f"unsigned int n_{self.c_n    150             ri.cw.p(f"unsigned int n_{self.c_name};")
145         member = self._complex_member_type(ri)    151         member = self._complex_member_type(ri)
146         if member:                                152         if member:
147             ptr = '*' if self.is_multi_val() e    153             ptr = '*' if self.is_multi_val() else ''
148             if self.is_recursive_for_op(ri):      154             if self.is_recursive_for_op(ri):
149                 ptr = '*'                         155                 ptr = '*'
150             ri.cw.p(f"{member} {ptr}{self.c_na    156             ri.cw.p(f"{member} {ptr}{self.c_name};")
151             return                                157             return
152         members = self.arg_member(ri)             158         members = self.arg_member(ri)
153         for one in members:                       159         for one in members:
154             ri.cw.p(one + ';')                    160             ri.cw.p(one + ';')
155                                                   161 
156     def _attr_policy(self, policy):               162     def _attr_policy(self, policy):
157         return '{ .type = ' + policy + ', }'      163         return '{ .type = ' + policy + ', }'
158                                                   164 
159     def attr_policy(self, cw):                    165     def attr_policy(self, cw):
160         policy = c_upper('nla-' + self.attr['t    166         policy = c_upper('nla-' + self.attr['type'])
161                                                   167 
162         spec = self._attr_policy(policy)          168         spec = self._attr_policy(policy)
163         cw.p(f"\t[{self.enum_name}] = {spec},"    169         cw.p(f"\t[{self.enum_name}] = {spec},")
164                                                   170 
                                                   >> 171     def _mnl_type(self):
                                                   >> 172         # mnl does not have helpers for signed integer types
                                                   >> 173         # turn signed type into unsigned
                                                   >> 174         # this only makes sense for scalar types
                                                   >> 175         t = self.type
                                                   >> 176         if t[0] == 's':
                                                   >> 177             t = 'u' + t[1:]
                                                   >> 178         return t
                                                   >> 179 
165     def _attr_typol(self):                        180     def _attr_typol(self):
166         raise Exception(f"Type policy not impl    181         raise Exception(f"Type policy not implemented for class type {self.type}")
167                                                   182 
168     def attr_typol(self, cw):                     183     def attr_typol(self, cw):
169         typol = self._attr_typol()                184         typol = self._attr_typol()
170         cw.p(f'[{self.enum_name}] = {"{"} .nam    185         cw.p(f'[{self.enum_name}] = {"{"} .name = "{self.name}", {typol}{"}"},')
171                                                   186 
172     def _attr_put_line(self, ri, var, line):      187     def _attr_put_line(self, ri, var, line):
173         if self.presence_type() == 'bit':         188         if self.presence_type() == 'bit':
174             ri.cw.p(f"if ({var}->_present.{sel    189             ri.cw.p(f"if ({var}->_present.{self.c_name})")
175         elif self.presence_type() == 'len':       190         elif self.presence_type() == 'len':
176             ri.cw.p(f"if ({var}->_present.{sel    191             ri.cw.p(f"if ({var}->_present.{self.c_name}_len)")
177         ri.cw.p(f"{line};")                       192         ri.cw.p(f"{line};")
178                                                   193 
179     def _attr_put_simple(self, ri, var, put_ty    194     def _attr_put_simple(self, ri, var, put_type):
180         line = f"ynl_attr_put_{put_type}(nlh,  !! 195         line = f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})"
181         self._attr_put_line(ri, var, line)        196         self._attr_put_line(ri, var, line)
182                                                   197 
183     def attr_put(self, ri, var):                  198     def attr_put(self, ri, var):
184         raise Exception(f"Put not implemented     199         raise Exception(f"Put not implemented for class type {self.type}")
185                                                   200 
186     def _attr_get(self, ri, var):                 201     def _attr_get(self, ri, var):
187         raise Exception(f"Attr get not impleme    202         raise Exception(f"Attr get not implemented for class type {self.type}")
188                                                   203 
189     def attr_get(self, ri, var, first):           204     def attr_get(self, ri, var, first):
190         lines, init_lines, local_vars = self._    205         lines, init_lines, local_vars = self._attr_get(ri, var)
191         if type(lines) is str:                    206         if type(lines) is str:
192             lines = [lines]                       207             lines = [lines]
193         if type(init_lines) is str:               208         if type(init_lines) is str:
194             init_lines = [init_lines]             209             init_lines = [init_lines]
195                                                   210 
196         kw = 'if' if first else 'else if'         211         kw = 'if' if first else 'else if'
197         ri.cw.block_start(line=f"{kw} (type ==    212         ri.cw.block_start(line=f"{kw} (type == {self.enum_name})")
198         if local_vars:                            213         if local_vars:
199             for local in local_vars:              214             for local in local_vars:
200                 ri.cw.p(local)                    215                 ri.cw.p(local)
201             ri.cw.nl()                            216             ri.cw.nl()
202                                                   217 
203         if not self.is_multi_val():               218         if not self.is_multi_val():
204             ri.cw.p("if (ynl_attr_validate(yar    219             ri.cw.p("if (ynl_attr_validate(yarg, attr))")
205             ri.cw.p("return YNL_PARSE_CB_ERROR !! 220             ri.cw.p("return MNL_CB_ERROR;")
206             if self.presence_type() == 'bit':     221             if self.presence_type() == 'bit':
207                 ri.cw.p(f"{var}->_present.{sel    222                 ri.cw.p(f"{var}->_present.{self.c_name} = 1;")
208                                                   223 
209         if init_lines:                            224         if init_lines:
210             ri.cw.nl()                            225             ri.cw.nl()
211             for line in init_lines:               226             for line in init_lines:
212                 ri.cw.p(line)                     227                 ri.cw.p(line)
213                                                   228 
214         for line in lines:                        229         for line in lines:
215             ri.cw.p(line)                         230             ri.cw.p(line)
216         ri.cw.block_end()                         231         ri.cw.block_end()
217         return True                               232         return True
218                                                   233 
219     def _setter_lines(self, ri, member, presen    234     def _setter_lines(self, ri, member, presence):
220         raise Exception(f"Setter not implement    235         raise Exception(f"Setter not implemented for class type {self.type}")
221                                                   236 
222     def setter(self, ri, space, direction, der    237     def setter(self, ri, space, direction, deref=False, ref=None):
223         ref = (ref if ref else []) + [self.c_n    238         ref = (ref if ref else []) + [self.c_name]
224         var = "req"                               239         var = "req"
225         member = f"{var}->{'.'.join(ref)}"        240         member = f"{var}->{'.'.join(ref)}"
226                                                   241 
227         code = []                                 242         code = []
228         presence = ''                             243         presence = ''
229         for i in range(0, len(ref)):              244         for i in range(0, len(ref)):
230             presence = f"{var}->{'.'.join(ref[    245             presence = f"{var}->{'.'.join(ref[:i] + [''])}_present.{ref[i]}"
231             # Every layer below last is a nest    246             # Every layer below last is a nest, so we know it uses bit presence
232             # last layer is "self" and may be     247             # last layer is "self" and may be a complex type
233             if i == len(ref) - 1 and self.pres    248             if i == len(ref) - 1 and self.presence_type() != 'bit':
234                 continue                          249                 continue
235             code.append(presence + ' = 1;')       250             code.append(presence + ' = 1;')
236         code += self._setter_lines(ri, member,    251         code += self._setter_lines(ri, member, presence)
237                                                   252 
238         func_name = f"{op_prefix(ri, direction    253         func_name = f"{op_prefix(ri, direction, deref=deref)}_set_{'_'.join(ref)}"
239         free = bool([x for x in code if 'free(    254         free = bool([x for x in code if 'free(' in x])
240         alloc = bool([x for x in code if 'allo    255         alloc = bool([x for x in code if 'alloc(' in x])
241         if free and not alloc:                    256         if free and not alloc:
242             func_name = '__' + func_name          257             func_name = '__' + func_name
243         ri.cw.write_func('static inline void',    258         ri.cw.write_func('static inline void', func_name, body=code,
244                          args=[f'{type_name(ri    259                          args=[f'{type_name(ri, direction, deref=deref)} *{var}'] + self.arg_member(ri))
245                                                   260 
246                                                   261 
247 class TypeUnused(Type):                           262 class TypeUnused(Type):
248     def presence_type(self):                      263     def presence_type(self):
249         return ''                                 264         return ''
250                                                   265 
251     def arg_member(self, ri):                     266     def arg_member(self, ri):
252         return []                                 267         return []
253                                                   268 
254     def _attr_get(self, ri, var):                 269     def _attr_get(self, ri, var):
255         return ['return YNL_PARSE_CB_ERROR;'], !! 270         return ['return MNL_CB_ERROR;'], None, None
256                                                   271 
257     def _attr_typol(self):                        272     def _attr_typol(self):
258         return '.type = YNL_PT_REJECT, '          273         return '.type = YNL_PT_REJECT, '
259                                                   274 
260     def attr_policy(self, cw):                    275     def attr_policy(self, cw):
261         pass                                      276         pass
262                                                   277 
263     def attr_put(self, ri, var):                  278     def attr_put(self, ri, var):
264         pass                                      279         pass
265                                                   280 
266     def attr_get(self, ri, var, first):           281     def attr_get(self, ri, var, first):
267         pass                                      282         pass
268                                                   283 
269     def setter(self, ri, space, direction, der    284     def setter(self, ri, space, direction, deref=False, ref=None):
270         pass                                      285         pass
271                                                   286 
272                                                   287 
273 class TypePad(Type):                              288 class TypePad(Type):
274     def presence_type(self):                      289     def presence_type(self):
275         return ''                                 290         return ''
276                                                   291 
277     def arg_member(self, ri):                     292     def arg_member(self, ri):
278         return []                                 293         return []
279                                                   294 
280     def _attr_typol(self):                        295     def _attr_typol(self):
281         return '.type = YNL_PT_IGNORE, '          296         return '.type = YNL_PT_IGNORE, '
282                                                   297 
283     def attr_put(self, ri, var):                  298     def attr_put(self, ri, var):
284         pass                                      299         pass
285                                                   300 
286     def attr_get(self, ri, var, first):           301     def attr_get(self, ri, var, first):
287         pass                                      302         pass
288                                                   303 
289     def attr_policy(self, cw):                    304     def attr_policy(self, cw):
290         pass                                      305         pass
291                                                   306 
292     def setter(self, ri, space, direction, der    307     def setter(self, ri, space, direction, deref=False, ref=None):
293         pass                                      308         pass
294                                                   309 
295                                                   310 
296 class TypeScalar(Type):                           311 class TypeScalar(Type):
297     def __init__(self, family, attr_set, attr,    312     def __init__(self, family, attr_set, attr, value):
298         super().__init__(family, attr_set, att    313         super().__init__(family, attr_set, attr, value)
299                                                   314 
300         self.byte_order_comment = ''              315         self.byte_order_comment = ''
301         if 'byte-order' in attr:                  316         if 'byte-order' in attr:
302             self.byte_order_comment = f" /* {a    317             self.byte_order_comment = f" /* {attr['byte-order']} */"
303                                                   318 
304         if 'enum' in self.attr:                   319         if 'enum' in self.attr:
305             enum = self.family.consts[self.att    320             enum = self.family.consts[self.attr['enum']]
306             low, high = enum.value_range()        321             low, high = enum.value_range()
307             if 'min' not in self.checks:          322             if 'min' not in self.checks:
308                 if low != 0 or self.type[0] ==    323                 if low != 0 or self.type[0] == 's':
309                     self.checks['min'] = low      324                     self.checks['min'] = low
310             if 'max' not in self.checks:          325             if 'max' not in self.checks:
311                 self.checks['max'] = high         326                 self.checks['max'] = high
312                                                   327 
313         if 'min' in self.checks and 'max' in s    328         if 'min' in self.checks and 'max' in self.checks:
314             if self.get_limit('min') > self.ge    329             if self.get_limit('min') > self.get_limit('max'):
315                 raise Exception(f'Invalid limi    330                 raise Exception(f'Invalid limit for "{self.name}" min: {self.get_limit("min")} max: {self.get_limit("max")}')
316             self.checks['range'] = True           331             self.checks['range'] = True
317                                                   332 
318         low = min(self.get_limit('min', 0), se    333         low = min(self.get_limit('min', 0), self.get_limit('max', 0))
319         high = max(self.get_limit('min', 0), s    334         high = max(self.get_limit('min', 0), self.get_limit('max', 0))
320         if low < 0 and self.type[0] == 'u':       335         if low < 0 and self.type[0] == 'u':
321             raise Exception(f'Invalid limit fo    336             raise Exception(f'Invalid limit for "{self.name}" negative limit for unsigned type')
322         if low < -32768 or high > 32767:          337         if low < -32768 or high > 32767:
323             self.checks['full-range'] = True      338             self.checks['full-range'] = True
324                                                   339 
325         # Added by resolve():                     340         # Added by resolve():
326         self.is_bitfield = None                   341         self.is_bitfield = None
327         delattr(self, "is_bitfield")              342         delattr(self, "is_bitfield")
328         self.type_name = None                     343         self.type_name = None
329         delattr(self, "type_name")                344         delattr(self, "type_name")
330                                                   345 
331     def resolve(self):                            346     def resolve(self):
332         self.resolve_up(super())                  347         self.resolve_up(super())
333                                                   348 
334         if 'enum-as-flags' in self.attr and se    349         if 'enum-as-flags' in self.attr and self.attr['enum-as-flags']:
335             self.is_bitfield = True               350             self.is_bitfield = True
336         elif 'enum' in self.attr:                 351         elif 'enum' in self.attr:
337             self.is_bitfield = self.family.con    352             self.is_bitfield = self.family.consts[self.attr['enum']]['type'] == 'flags'
338         else:                                     353         else:
339             self.is_bitfield = False              354             self.is_bitfield = False
340                                                   355 
341         if not self.is_bitfield and 'enum' in     356         if not self.is_bitfield and 'enum' in self.attr:
342             self.type_name = self.family.const    357             self.type_name = self.family.consts[self.attr['enum']].user_type
343         elif self.is_auto_scalar:                 358         elif self.is_auto_scalar:
344             self.type_name = '__' + self.type[    359             self.type_name = '__' + self.type[0] + '64'
345         else:                                     360         else:
346             self.type_name = '__' + self.type     361             self.type_name = '__' + self.type
347                                                   362 
                                                   >> 363     def mnl_type(self):
                                                   >> 364         return self._mnl_type()
                                                   >> 365 
348     def _attr_policy(self, policy):               366     def _attr_policy(self, policy):
349         if 'flags-mask' in self.checks or self    367         if 'flags-mask' in self.checks or self.is_bitfield:
350             if self.is_bitfield:                  368             if self.is_bitfield:
351                 enum = self.family.consts[self    369                 enum = self.family.consts[self.attr['enum']]
352                 mask = enum.get_mask(as_flags=    370                 mask = enum.get_mask(as_flags=True)
353             else:                                 371             else:
354                 flags = self.family.consts[sel    372                 flags = self.family.consts[self.checks['flags-mask']]
355                 flag_cnt = len(flags['entries'    373                 flag_cnt = len(flags['entries'])
356                 mask = (1 << flag_cnt) - 1        374                 mask = (1 << flag_cnt) - 1
357             return f"NLA_POLICY_MASK({policy},    375             return f"NLA_POLICY_MASK({policy}, 0x{mask:x})"
358         elif 'full-range' in self.checks:         376         elif 'full-range' in self.checks:
359             return f"NLA_POLICY_FULL_RANGE({po    377             return f"NLA_POLICY_FULL_RANGE({policy}, &{c_lower(self.enum_name)}_range)"
360         elif 'range' in self.checks:              378         elif 'range' in self.checks:
361             return f"NLA_POLICY_RANGE({policy}    379             return f"NLA_POLICY_RANGE({policy}, {self.get_limit('min')}, {self.get_limit('max')})"
362         elif 'min' in self.checks:                380         elif 'min' in self.checks:
363             return f"NLA_POLICY_MIN({policy},     381             return f"NLA_POLICY_MIN({policy}, {self.get_limit('min')})"
364         elif 'max' in self.checks:                382         elif 'max' in self.checks:
365             return f"NLA_POLICY_MAX({policy},     383             return f"NLA_POLICY_MAX({policy}, {self.get_limit('max')})"
366         return super()._attr_policy(policy)       384         return super()._attr_policy(policy)
367                                                   385 
368     def _attr_typol(self):                        386     def _attr_typol(self):
369         return f'.type = YNL_PT_U{c_upper(self    387         return f'.type = YNL_PT_U{c_upper(self.type[1:])}, '
370                                                   388 
371     def arg_member(self, ri):                     389     def arg_member(self, ri):
372         return [f'{self.type_name} {self.c_nam    390         return [f'{self.type_name} {self.c_name}{self.byte_order_comment}']
373                                                   391 
374     def attr_put(self, ri, var):                  392     def attr_put(self, ri, var):
375         self._attr_put_simple(ri, var, self.ty !! 393         self._attr_put_simple(ri, var, self.mnl_type())
376                                                   394 
377     def _attr_get(self, ri, var):                 395     def _attr_get(self, ri, var):
378         return f"{var}->{self.c_name} = ynl_at !! 396         return f"{var}->{self.c_name} = mnl_attr_get_{self.mnl_type()}(attr);", None, None
379                                                   397 
380     def _setter_lines(self, ri, member, presen    398     def _setter_lines(self, ri, member, presence):
381         return [f"{member} = {self.c_name};"]     399         return [f"{member} = {self.c_name};"]
382                                                   400 
383                                                   401 
384 class TypeFlag(Type):                             402 class TypeFlag(Type):
385     def arg_member(self, ri):                     403     def arg_member(self, ri):
386         return []                                 404         return []
387                                                   405 
388     def _attr_typol(self):                        406     def _attr_typol(self):
389         return '.type = YNL_PT_FLAG, '            407         return '.type = YNL_PT_FLAG, '
390                                                   408 
391     def attr_put(self, ri, var):                  409     def attr_put(self, ri, var):
392         self._attr_put_line(ri, var, f"ynl_att !! 410         self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, 0, NULL)")
393                                                   411 
394     def _attr_get(self, ri, var):                 412     def _attr_get(self, ri, var):
395         return [], None, None                     413         return [], None, None
396                                                   414 
397     def _setter_lines(self, ri, member, presen    415     def _setter_lines(self, ri, member, presence):
398         return []                                 416         return []
399                                                   417 
400                                                   418 
401 class TypeString(Type):                           419 class TypeString(Type):
402     def arg_member(self, ri):                     420     def arg_member(self, ri):
403         return [f"const char *{self.c_name}"]     421         return [f"const char *{self.c_name}"]
404                                                   422 
405     def presence_type(self):                      423     def presence_type(self):
406         return 'len'                              424         return 'len'
407                                                   425 
408     def struct_member(self, ri):                  426     def struct_member(self, ri):
409         ri.cw.p(f"char *{self.c_name};")          427         ri.cw.p(f"char *{self.c_name};")
410                                                   428 
411     def _attr_typol(self):                        429     def _attr_typol(self):
412         return f'.type = YNL_PT_NUL_STR, '        430         return f'.type = YNL_PT_NUL_STR, '
413                                                   431 
414     def _attr_policy(self, policy):               432     def _attr_policy(self, policy):
415         if 'exact-len' in self.checks:            433         if 'exact-len' in self.checks:
416             mem = 'NLA_POLICY_EXACT_LEN(' + st !! 434             mem = 'NLA_POLICY_EXACT_LEN(' + str(self.checks['exact-len']) + ')'
417         else:                                     435         else:
418             mem = '{ .type = ' + policy           436             mem = '{ .type = ' + policy
419             if 'max-len' in self.checks:          437             if 'max-len' in self.checks:
420                 mem += ', .len = ' + str(self.    438                 mem += ', .len = ' + str(self.get_limit('max-len'))
421             mem += ', }'                          439             mem += ', }'
422         return mem                                440         return mem
423                                                   441 
424     def attr_policy(self, cw):                    442     def attr_policy(self, cw):
425         if self.checks.get('unterminated-ok',     443         if self.checks.get('unterminated-ok', False):
426             policy = 'NLA_STRING'                 444             policy = 'NLA_STRING'
427         else:                                     445         else:
428             policy = 'NLA_NUL_STRING'             446             policy = 'NLA_NUL_STRING'
429                                                   447 
430         spec = self._attr_policy(policy)          448         spec = self._attr_policy(policy)
431         cw.p(f"\t[{self.enum_name}] = {spec},"    449         cw.p(f"\t[{self.enum_name}] = {spec},")
432                                                   450 
433     def attr_put(self, ri, var):                  451     def attr_put(self, ri, var):
434         self._attr_put_simple(ri, var, 'str')  !! 452         self._attr_put_simple(ri, var, 'strz')
435                                                   453 
436     def _attr_get(self, ri, var):                 454     def _attr_get(self, ri, var):
437         len_mem = var + '->_present.' + self.c    455         len_mem = var + '->_present.' + self.c_name + '_len'
438         return [f"{len_mem} = len;",              456         return [f"{len_mem} = len;",
439                 f"{var}->{self.c_name} = mallo    457                 f"{var}->{self.c_name} = malloc(len + 1);",
440                 f"memcpy({var}->{self.c_name}, !! 458                 f"memcpy({var}->{self.c_name}, mnl_attr_get_str(attr), len);",
441                 f"{var}->{self.c_name}[len] =     459                 f"{var}->{self.c_name}[len] = 0;"], \
442                ['len = strnlen(ynl_attr_get_st !! 460                ['len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));'], \
443                ['unsigned int len;']              461                ['unsigned int len;']
444                                                   462 
445     def _setter_lines(self, ri, member, presen    463     def _setter_lines(self, ri, member, presence):
446         return [f"free({member});",               464         return [f"free({member});",
447                 f"{presence}_len = strlen({sel    465                 f"{presence}_len = strlen({self.c_name});",
448                 f"{member} = malloc({presence}    466                 f"{member} = malloc({presence}_len + 1);",
449                 f'memcpy({member}, {self.c_nam    467                 f'memcpy({member}, {self.c_name}, {presence}_len);',
450                 f'{member}[{presence}_len] = 0    468                 f'{member}[{presence}_len] = 0;']
451                                                   469 
452                                                   470 
453 class TypeBinary(Type):                           471 class TypeBinary(Type):
454     def arg_member(self, ri):                     472     def arg_member(self, ri):
455         return [f"const void *{self.c_name}",     473         return [f"const void *{self.c_name}", 'size_t len']
456                                                   474 
457     def presence_type(self):                      475     def presence_type(self):
458         return 'len'                              476         return 'len'
459                                                   477 
460     def struct_member(self, ri):                  478     def struct_member(self, ri):
461         ri.cw.p(f"void *{self.c_name};")          479         ri.cw.p(f"void *{self.c_name};")
462                                                   480 
463     def _attr_typol(self):                        481     def _attr_typol(self):
464         return f'.type = YNL_PT_BINARY,'          482         return f'.type = YNL_PT_BINARY,'
465                                                   483 
466     def _attr_policy(self, policy):               484     def _attr_policy(self, policy):
467         if 'exact-len' in self.checks:            485         if 'exact-len' in self.checks:
468             mem = 'NLA_POLICY_EXACT_LEN(' + st !! 486             mem = 'NLA_POLICY_EXACT_LEN(' + str(self.checks['exact-len']) + ')'
469         else:                                     487         else:
470             mem = '{ '                            488             mem = '{ '
471             if len(self.checks) == 1 and 'min-    489             if len(self.checks) == 1 and 'min-len' in self.checks:
472                 mem += '.len = ' + str(self.ge    490                 mem += '.len = ' + str(self.get_limit('min-len'))
473             elif len(self.checks) == 0:           491             elif len(self.checks) == 0:
474                 mem += '.type = NLA_BINARY'       492                 mem += '.type = NLA_BINARY'
475             else:                                 493             else:
476                 raise Exception('One or more o    494                 raise Exception('One or more of binary type checks not implemented, yet')
477             mem += ', }'                          495             mem += ', }'
478         return mem                                496         return mem
479                                                   497 
480     def attr_put(self, ri, var):                  498     def attr_put(self, ri, var):
481         self._attr_put_line(ri, var, f"ynl_att !! 499         self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, " +
482                             f"{var}->{self.c_n !! 500                             f"{var}->_present.{self.c_name}_len, {var}->{self.c_name})")
483                                                   501 
484     def _attr_get(self, ri, var):                 502     def _attr_get(self, ri, var):
485         len_mem = var + '->_present.' + self.c    503         len_mem = var + '->_present.' + self.c_name + '_len'
486         return [f"{len_mem} = len;",              504         return [f"{len_mem} = len;",
487                 f"{var}->{self.c_name} = mallo    505                 f"{var}->{self.c_name} = malloc(len);",
488                 f"memcpy({var}->{self.c_name}, !! 506                 f"memcpy({var}->{self.c_name}, mnl_attr_get_payload(attr), len);"], \
489                ['len = ynl_attr_data_len(attr) !! 507                ['len = mnl_attr_get_payload_len(attr);'], \
490                ['unsigned int len;']              508                ['unsigned int len;']
491                                                   509 
492     def _setter_lines(self, ri, member, presen    510     def _setter_lines(self, ri, member, presence):
493         return [f"free({member});",               511         return [f"free({member});",
494                 f"{presence}_len = len;",         512                 f"{presence}_len = len;",
495                 f"{member} = malloc({presence}    513                 f"{member} = malloc({presence}_len);",
496                 f'memcpy({member}, {self.c_nam    514                 f'memcpy({member}, {self.c_name}, {presence}_len);']
497                                                   515 
498                                                   516 
499 class TypeBitfield32(Type):                       517 class TypeBitfield32(Type):
500     def _complex_member_type(self, ri):           518     def _complex_member_type(self, ri):
501         return "struct nla_bitfield32"            519         return "struct nla_bitfield32"
502                                                   520 
503     def _attr_typol(self):                        521     def _attr_typol(self):
504         return f'.type = YNL_PT_BITFIELD32, '     522         return f'.type = YNL_PT_BITFIELD32, '
505                                                   523 
506     def _attr_policy(self, policy):               524     def _attr_policy(self, policy):
507         if not 'enum' in self.attr:               525         if not 'enum' in self.attr:
508             raise Exception('Enum required for    526             raise Exception('Enum required for bitfield32 attr')
509         enum = self.family.consts[self.attr['e    527         enum = self.family.consts[self.attr['enum']]
510         mask = enum.get_mask(as_flags=True)       528         mask = enum.get_mask(as_flags=True)
511         return f"NLA_POLICY_BITFIELD32({mask})    529         return f"NLA_POLICY_BITFIELD32({mask})"
512                                                   530 
513     def attr_put(self, ri, var):                  531     def attr_put(self, ri, var):
514         line = f"ynl_attr_put(nlh, {self.enum_ !! 532         line = f"mnl_attr_put(nlh, {self.enum_name}, sizeof(struct nla_bitfield32), &{var}->{self.c_name})"
515         self._attr_put_line(ri, var, line)        533         self._attr_put_line(ri, var, line)
516                                                   534 
517     def _attr_get(self, ri, var):                 535     def _attr_get(self, ri, var):
518         return f"memcpy(&{var}->{self.c_name}, !! 536         return f"memcpy(&{var}->{self.c_name}, mnl_attr_get_payload(attr), sizeof(struct nla_bitfield32));", None, None
519                                                   537 
520     def _setter_lines(self, ri, member, presen    538     def _setter_lines(self, ri, member, presence):
521         return [f"memcpy(&{member}, {self.c_na    539         return [f"memcpy(&{member}, {self.c_name}, sizeof(struct nla_bitfield32));"]
522                                                   540 
523                                                   541 
524 class TypeNest(Type):                             542 class TypeNest(Type):
525     def is_recursive(self):                       543     def is_recursive(self):
526         return self.family.pure_nested_structs    544         return self.family.pure_nested_structs[self.nested_attrs].recursive
527                                                   545 
528     def _complex_member_type(self, ri):           546     def _complex_member_type(self, ri):
529         return self.nested_struct_type            547         return self.nested_struct_type
530                                                   548 
531     def free(self, ri, var, ref):                 549     def free(self, ri, var, ref):
532         at = '&'                                  550         at = '&'
533         if self.is_recursive_for_op(ri):          551         if self.is_recursive_for_op(ri):
534             at = ''                               552             at = ''
535             ri.cw.p(f'if ({var}->{ref}{self.c_    553             ri.cw.p(f'if ({var}->{ref}{self.c_name})')
536         ri.cw.p(f'{self.nested_render_name}_fr    554         ri.cw.p(f'{self.nested_render_name}_free({at}{var}->{ref}{self.c_name});')
537                                                   555 
538     def _attr_typol(self):                        556     def _attr_typol(self):
539         return f'.type = YNL_PT_NEST, .nest =     557         return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
540                                                   558 
541     def _attr_policy(self, policy):               559     def _attr_policy(self, policy):
542         return 'NLA_POLICY_NESTED(' + self.nes    560         return 'NLA_POLICY_NESTED(' + self.nested_render_name + '_nl_policy)'
543                                                   561 
544     def attr_put(self, ri, var):                  562     def attr_put(self, ri, var):
545         at = '' if self.is_recursive_for_op(ri    563         at = '' if self.is_recursive_for_op(ri) else '&'
546         self._attr_put_line(ri, var, f"{self.n    564         self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " +
547                             f"{self.enum_name}    565                             f"{self.enum_name}, {at}{var}->{self.c_name})")
548                                                   566 
549     def _attr_get(self, ri, var):                 567     def _attr_get(self, ri, var):
550         get_lines = [f"if ({self.nested_render    568         get_lines = [f"if ({self.nested_render_name}_parse(&parg, attr))",
551                      "return YNL_PARSE_CB_ERRO !! 569                      "return MNL_CB_ERROR;"]
552         init_lines = [f"parg.rsp_policy = &{se    570         init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;",
553                       f"parg.data = &{var}->{s    571                       f"parg.data = &{var}->{self.c_name};"]
554         return get_lines, init_lines, None        572         return get_lines, init_lines, None
555                                                   573 
556     def setter(self, ri, space, direction, der    574     def setter(self, ri, space, direction, deref=False, ref=None):
557         ref = (ref if ref else []) + [self.c_n    575         ref = (ref if ref else []) + [self.c_name]
558                                                   576 
559         for _, attr in ri.family.pure_nested_s    577         for _, attr in ri.family.pure_nested_structs[self.nested_attrs].member_list():
560             if attr.is_recursive():               578             if attr.is_recursive():
561                 continue                          579                 continue
562             attr.setter(ri, self.nested_attrs,    580             attr.setter(ri, self.nested_attrs, direction, deref=deref, ref=ref)
563                                                   581 
564                                                   582 
565 class TypeMultiAttr(Type):                        583 class TypeMultiAttr(Type):
566     def __init__(self, family, attr_set, attr,    584     def __init__(self, family, attr_set, attr, value, base_type):
567         super().__init__(family, attr_set, att    585         super().__init__(family, attr_set, attr, value)
568                                                   586 
569         self.base_type = base_type                587         self.base_type = base_type
570                                                   588 
571     def is_multi_val(self):                       589     def is_multi_val(self):
572         return True                               590         return True
573                                                   591 
574     def presence_type(self):                      592     def presence_type(self):
575         return 'count'                            593         return 'count'
576                                                   594 
                                                   >> 595     def mnl_type(self):
                                                   >> 596         return self._mnl_type()
                                                   >> 597 
577     def _complex_member_type(self, ri):           598     def _complex_member_type(self, ri):
578         if 'type' not in self.attr or self.att    599         if 'type' not in self.attr or self.attr['type'] == 'nest':
579             return self.nested_struct_type        600             return self.nested_struct_type
580         elif self.attr['type'] in scalars:        601         elif self.attr['type'] in scalars:
581             scalar_pfx = '__' if ri.ku_space =    602             scalar_pfx = '__' if ri.ku_space == 'user' else ''
582             return scalar_pfx + self.attr['typ    603             return scalar_pfx + self.attr['type']
583         else:                                     604         else:
584             raise Exception(f"Sub-type {self.a    605             raise Exception(f"Sub-type {self.attr['type']} not supported yet")
585                                                   606 
586     def free_needs_iter(self):                    607     def free_needs_iter(self):
587         return 'type' not in self.attr or self    608         return 'type' not in self.attr or self.attr['type'] == 'nest'
588                                                   609 
589     def free(self, ri, var, ref):                 610     def free(self, ri, var, ref):
590         if self.attr['type'] in scalars:          611         if self.attr['type'] in scalars:
591             ri.cw.p(f"free({var}->{ref}{self.c    612             ri.cw.p(f"free({var}->{ref}{self.c_name});")
592         elif 'type' not in self.attr or self.a    613         elif 'type' not in self.attr or self.attr['type'] == 'nest':
593             ri.cw.p(f"for (i = 0; i < {var}->{    614             ri.cw.p(f"for (i = 0; i < {var}->{ref}n_{self.c_name}; i++)")
594             ri.cw.p(f'{self.nested_render_name    615             ri.cw.p(f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);')
595             ri.cw.p(f"free({var}->{ref}{self.c    616             ri.cw.p(f"free({var}->{ref}{self.c_name});")
596         else:                                     617         else:
597             raise Exception(f"Free of MultiAtt    618             raise Exception(f"Free of MultiAttr sub-type {self.attr['type']} not supported yet")
598                                                   619 
599     def _attr_policy(self, policy):               620     def _attr_policy(self, policy):
600         return self.base_type._attr_policy(pol    621         return self.base_type._attr_policy(policy)
601                                                   622 
602     def _attr_typol(self):                        623     def _attr_typol(self):
603         return self.base_type._attr_typol()       624         return self.base_type._attr_typol()
604                                                   625 
605     def _attr_get(self, ri, var):                 626     def _attr_get(self, ri, var):
606         return f'n_{self.c_name}++;', None, No    627         return f'n_{self.c_name}++;', None, None
607                                                   628 
608     def attr_put(self, ri, var):                  629     def attr_put(self, ri, var):
609         if self.attr['type'] in scalars:          630         if self.attr['type'] in scalars:
610             put_type = self.type               !! 631             put_type = self.mnl_type()
611             ri.cw.p(f"for (unsigned int i = 0;    632             ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)")
612             ri.cw.p(f"ynl_attr_put_{put_type}( !! 633             ri.cw.p(f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);")
613         elif 'type' not in self.attr or self.a    634         elif 'type' not in self.attr or self.attr['type'] == 'nest':
614             ri.cw.p(f"for (unsigned int i = 0;    635             ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)")
615             self._attr_put_line(ri, var, f"{se    636             self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " +
616                                 f"{self.enum_n    637                                 f"{self.enum_name}, &{var}->{self.c_name}[i])")
617         else:                                     638         else:
618             raise Exception(f"Put of MultiAttr    639             raise Exception(f"Put of MultiAttr sub-type {self.attr['type']} not supported yet")
619                                                   640 
620     def _setter_lines(self, ri, member, presen    641     def _setter_lines(self, ri, member, presence):
621         # For multi-attr we have a count, not     642         # For multi-attr we have a count, not presence, hack up the presence
622         presence = presence[:-(len('_present.'    643         presence = presence[:-(len('_present.') + len(self.c_name))] + "n_" + self.c_name
623         return [f"free({member});",               644         return [f"free({member});",
624                 f"{member} = {self.c_name};",     645                 f"{member} = {self.c_name};",
625                 f"{presence} = n_{self.c_name}    646                 f"{presence} = n_{self.c_name};"]
626                                                   647 
627                                                   648 
628 class TypeArrayNest(Type):                        649 class TypeArrayNest(Type):
629     def is_multi_val(self):                       650     def is_multi_val(self):
630         return True                               651         return True
631                                                   652 
632     def presence_type(self):                      653     def presence_type(self):
633         return 'count'                            654         return 'count'
634                                                   655 
635     def _complex_member_type(self, ri):           656     def _complex_member_type(self, ri):
636         if 'sub-type' not in self.attr or self    657         if 'sub-type' not in self.attr or self.attr['sub-type'] == 'nest':
637             return self.nested_struct_type        658             return self.nested_struct_type
638         elif self.attr['sub-type'] in scalars:    659         elif self.attr['sub-type'] in scalars:
639             scalar_pfx = '__' if ri.ku_space =    660             scalar_pfx = '__' if ri.ku_space == 'user' else ''
640             return scalar_pfx + self.attr['sub    661             return scalar_pfx + self.attr['sub-type']
641         else:                                     662         else:
642             raise Exception(f"Sub-type {self.a    663             raise Exception(f"Sub-type {self.attr['sub-type']} not supported yet")
643                                                   664 
644     def _attr_typol(self):                        665     def _attr_typol(self):
645         return f'.type = YNL_PT_NEST, .nest =     666         return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
646                                                   667 
647     def _attr_get(self, ri, var):                 668     def _attr_get(self, ri, var):
648         local_vars = ['const struct nlattr *at    669         local_vars = ['const struct nlattr *attr2;']
649         get_lines = [f'attr_{self.c_name} = at    670         get_lines = [f'attr_{self.c_name} = attr;',
650                      'ynl_attr_for_each_nested !! 671                      'mnl_attr_for_each_nested(attr2, attr)',
651                      f'\t{var}->n_{self.c_name    672                      f'\t{var}->n_{self.c_name}++;']
652         return get_lines, None, local_vars        673         return get_lines, None, local_vars
653                                                   674 
654                                                   675 
655 class TypeNestTypeValue(Type):                    676 class TypeNestTypeValue(Type):
656     def _complex_member_type(self, ri):           677     def _complex_member_type(self, ri):
657         return self.nested_struct_type            678         return self.nested_struct_type
658                                                   679 
659     def _attr_typol(self):                        680     def _attr_typol(self):
660         return f'.type = YNL_PT_NEST, .nest =     681         return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
661                                                   682 
662     def _attr_get(self, ri, var):                 683     def _attr_get(self, ri, var):
663         prev = 'attr'                             684         prev = 'attr'
664         tv_args = ''                              685         tv_args = ''
665         get_lines = []                            686         get_lines = []
666         local_vars = []                           687         local_vars = []
667         init_lines = [f"parg.rsp_policy = &{se    688         init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;",
668                       f"parg.data = &{var}->{s    689                       f"parg.data = &{var}->{self.c_name};"]
669         if 'type-value' in self.attr:             690         if 'type-value' in self.attr:
670             tv_names = [c_lower(x) for x in se    691             tv_names = [c_lower(x) for x in self.attr["type-value"]]
671             local_vars += [f'const struct nlat    692             local_vars += [f'const struct nlattr *attr_{", *attr_".join(tv_names)};']
672             local_vars += [f'__u32 {", ".join(    693             local_vars += [f'__u32 {", ".join(tv_names)};']
673             for level in self.attr["type-value    694             for level in self.attr["type-value"]:
674                 level = c_lower(level)            695                 level = c_lower(level)
675                 get_lines += [f'attr_{level} = !! 696                 get_lines += [f'attr_{level} = mnl_attr_get_payload({prev});']
676                 get_lines += [f'{level} = ynl_ !! 697                 get_lines += [f'{level} = mnl_attr_get_type(attr_{level});']
677                 prev = 'attr_' + level            698                 prev = 'attr_' + level
678                                                   699 
679             tv_args = f", {', '.join(tv_names)    700             tv_args = f", {', '.join(tv_names)}"
680                                                   701 
681         get_lines += [f"{self.nested_render_na    702         get_lines += [f"{self.nested_render_name}_parse(&parg, {prev}{tv_args});"]
682         return get_lines, init_lines, local_va    703         return get_lines, init_lines, local_vars
683                                                   704 
684                                                   705 
685 class Struct:                                     706 class Struct:
686     def __init__(self, family, space_name, typ    707     def __init__(self, family, space_name, type_list=None, inherited=None):
687         self.family = family                      708         self.family = family
688         self.space_name = space_name              709         self.space_name = space_name
689         self.attr_set = family.attr_sets[space    710         self.attr_set = family.attr_sets[space_name]
690         # Use list to catch comparisons with e    711         # Use list to catch comparisons with empty sets
691         self._inherited = inherited if inherit    712         self._inherited = inherited if inherited is not None else []
692         self.inherited = []                       713         self.inherited = []
693                                                   714 
694         self.nested = type_list is None           715         self.nested = type_list is None
695         if family.name == c_lower(space_name):    716         if family.name == c_lower(space_name):
696             self.render_name = c_lower(family. !! 717             self.render_name = c_lower(family.name)
697         else:                                     718         else:
698             self.render_name = c_lower(family. !! 719             self.render_name = c_lower(family.name + '-' + space_name)
699         self.struct_name = 'struct ' + self.re    720         self.struct_name = 'struct ' + self.render_name
700         if self.nested and space_name in famil    721         if self.nested and space_name in family.consts:
701             self.struct_name += '_'               722             self.struct_name += '_'
702         self.ptr_name = self.struct_name + ' *    723         self.ptr_name = self.struct_name + ' *'
703         # All attr sets this one contains, dir    724         # All attr sets this one contains, directly or multiple levels down
704         self.child_nests = set()                  725         self.child_nests = set()
705                                                   726 
706         self.request = False                      727         self.request = False
707         self.reply = False                        728         self.reply = False
708         self.recursive = False                    729         self.recursive = False
709                                                   730 
710         self.attr_list = []                       731         self.attr_list = []
711         self.attrs = dict()                       732         self.attrs = dict()
712         if type_list is not None:                 733         if type_list is not None:
713             for t in type_list:                   734             for t in type_list:
714                 self.attr_list.append((t, self    735                 self.attr_list.append((t, self.attr_set[t]),)
715         else:                                     736         else:
716             for t in self.attr_set:               737             for t in self.attr_set:
717                 self.attr_list.append((t, self    738                 self.attr_list.append((t, self.attr_set[t]),)
718                                                   739 
719         max_val = 0                               740         max_val = 0
720         self.attr_max_val = None                  741         self.attr_max_val = None
721         for name, attr in self.attr_list:         742         for name, attr in self.attr_list:
722             if attr.value >= max_val:             743             if attr.value >= max_val:
723                 max_val = attr.value              744                 max_val = attr.value
724                 self.attr_max_val = attr          745                 self.attr_max_val = attr
725             self.attrs[name] = attr               746             self.attrs[name] = attr
726                                                   747 
727     def __iter__(self):                           748     def __iter__(self):
728         yield from self.attrs                     749         yield from self.attrs
729                                                   750 
730     def __getitem__(self, key):                   751     def __getitem__(self, key):
731         return self.attrs[key]                    752         return self.attrs[key]
732                                                   753 
733     def member_list(self):                        754     def member_list(self):
734         return self.attr_list                     755         return self.attr_list
735                                                   756 
736     def set_inherited(self, new_inherited):       757     def set_inherited(self, new_inherited):
737         if self._inherited != new_inherited:      758         if self._inherited != new_inherited:
738             raise Exception("Inheriting differ    759             raise Exception("Inheriting different members not supported")
739         self.inherited = [c_lower(x) for x in     760         self.inherited = [c_lower(x) for x in sorted(self._inherited)]
740                                                   761 
741                                                   762 
742 class EnumEntry(SpecEnumEntry):                   763 class EnumEntry(SpecEnumEntry):
743     def __init__(self, enum_set, yaml, prev, v    764     def __init__(self, enum_set, yaml, prev, value_start):
744         super().__init__(enum_set, yaml, prev,    765         super().__init__(enum_set, yaml, prev, value_start)
745                                                   766 
746         if prev:                                  767         if prev:
747             self.value_change = (self.value !=    768             self.value_change = (self.value != prev.value + 1)
748         else:                                     769         else:
749             self.value_change = (self.value !=    770             self.value_change = (self.value != 0)
750         self.value_change = self.value_change     771         self.value_change = self.value_change or self.enum_set['type'] == 'flags'
751                                                   772 
752         # Added by resolve:                       773         # Added by resolve:
753         self.c_name = None                        774         self.c_name = None
754         delattr(self, "c_name")                   775         delattr(self, "c_name")
755                                                   776 
756     def resolve(self):                            777     def resolve(self):
757         self.resolve_up(super())                  778         self.resolve_up(super())
758                                                   779 
759         self.c_name = c_upper(self.enum_set.va    780         self.c_name = c_upper(self.enum_set.value_pfx + self.name)
760                                                   781 
761                                                   782 
762 class EnumSet(SpecEnumSet):                       783 class EnumSet(SpecEnumSet):
763     def __init__(self, family, yaml):             784     def __init__(self, family, yaml):
764         self.render_name = c_lower(family.iden !! 785         self.render_name = c_lower(family.name + '-' + yaml['name'])
765                                                   786 
766         if 'enum-name' in yaml:                   787         if 'enum-name' in yaml:
767             if yaml['enum-name']:                 788             if yaml['enum-name']:
768                 self.enum_name = 'enum ' + c_l    789                 self.enum_name = 'enum ' + c_lower(yaml['enum-name'])
769                 self.user_type = self.enum_nam    790                 self.user_type = self.enum_name
770             else:                                 791             else:
771                 self.enum_name = None             792                 self.enum_name = None
772         else:                                     793         else:
773             self.enum_name = 'enum ' + self.re    794             self.enum_name = 'enum ' + self.render_name
774                                                   795 
775         if self.enum_name:                        796         if self.enum_name:
776             self.user_type = self.enum_name       797             self.user_type = self.enum_name
777         else:                                     798         else:
778             self.user_type = 'int'                799             self.user_type = 'int'
779                                                   800 
780         self.value_pfx = yaml.get('name-prefix !! 801         self.value_pfx = yaml.get('name-prefix', f"{family.name}-{yaml['name']}-")
781                                                   802 
782         super().__init__(family, yaml)            803         super().__init__(family, yaml)
783                                                   804 
784     def new_entry(self, entry, prev_entry, val    805     def new_entry(self, entry, prev_entry, value_start):
785         return EnumEntry(self, entry, prev_ent    806         return EnumEntry(self, entry, prev_entry, value_start)
786                                                   807 
787     def value_range(self):                        808     def value_range(self):
788         low = min([x.value for x in self.entri    809         low = min([x.value for x in self.entries.values()])
789         high = max([x.value for x in self.entr    810         high = max([x.value for x in self.entries.values()])
790                                                   811 
791         if high - low + 1 != len(self.entries)    812         if high - low + 1 != len(self.entries):
792             raise Exception("Can't get value r    813             raise Exception("Can't get value range for a noncontiguous enum")
793                                                   814 
794         return low, high                          815         return low, high
795                                                   816 
796                                                   817 
797 class AttrSet(SpecAttrSet):                       818 class AttrSet(SpecAttrSet):
798     def __init__(self, family, yaml):             819     def __init__(self, family, yaml):
799         super().__init__(family, yaml)            820         super().__init__(family, yaml)
800                                                   821 
801         if self.subset_of is None:                822         if self.subset_of is None:
802             if 'name-prefix' in yaml:             823             if 'name-prefix' in yaml:
803                 pfx = yaml['name-prefix']         824                 pfx = yaml['name-prefix']
804             elif self.name == family.name:        825             elif self.name == family.name:
805                 pfx = family.ident_name + '-a- !! 826                 pfx = family.name + '-a-'
806             else:                                 827             else:
807                 pfx = f"{family.ident_name}-a- !! 828                 pfx = f"{family.name}-a-{self.name}-"
808             self.name_prefix = c_upper(pfx)       829             self.name_prefix = c_upper(pfx)
809             self.max_name = c_upper(self.yaml.    830             self.max_name = c_upper(self.yaml.get('attr-max-name', f"{self.name_prefix}max"))
810             self.cnt_name = c_upper(self.yaml.    831             self.cnt_name = c_upper(self.yaml.get('attr-cnt-name', f"__{self.name_prefix}max"))
811         else:                                     832         else:
812             self.name_prefix = family.attr_set    833             self.name_prefix = family.attr_sets[self.subset_of].name_prefix
813             self.max_name = family.attr_sets[s    834             self.max_name = family.attr_sets[self.subset_of].max_name
814             self.cnt_name = family.attr_sets[s    835             self.cnt_name = family.attr_sets[self.subset_of].cnt_name
815                                                   836 
816         # Added by resolve:                       837         # Added by resolve:
817         self.c_name = None                        838         self.c_name = None
818         delattr(self, "c_name")                   839         delattr(self, "c_name")
819                                                   840 
820     def resolve(self):                            841     def resolve(self):
821         self.c_name = c_lower(self.name)          842         self.c_name = c_lower(self.name)
822         if self.c_name in _C_KW:                  843         if self.c_name in _C_KW:
823             self.c_name += '_'                    844             self.c_name += '_'
824         if self.c_name == self.family.c_name:     845         if self.c_name == self.family.c_name:
825             self.c_name = ''                      846             self.c_name = ''
826                                                   847 
827     def new_attr(self, elem, value):              848     def new_attr(self, elem, value):
828         if elem['type'] in scalars:               849         if elem['type'] in scalars:
829             t = TypeScalar(self.family, self,     850             t = TypeScalar(self.family, self, elem, value)
830         elif elem['type'] == 'unused':            851         elif elem['type'] == 'unused':
831             t = TypeUnused(self.family, self,     852             t = TypeUnused(self.family, self, elem, value)
832         elif elem['type'] == 'pad':               853         elif elem['type'] == 'pad':
833             t = TypePad(self.family, self, ele    854             t = TypePad(self.family, self, elem, value)
834         elif elem['type'] == 'flag':              855         elif elem['type'] == 'flag':
835             t = TypeFlag(self.family, self, el    856             t = TypeFlag(self.family, self, elem, value)
836         elif elem['type'] == 'string':            857         elif elem['type'] == 'string':
837             t = TypeString(self.family, self,     858             t = TypeString(self.family, self, elem, value)
838         elif elem['type'] == 'binary':            859         elif elem['type'] == 'binary':
839             t = TypeBinary(self.family, self,     860             t = TypeBinary(self.family, self, elem, value)
840         elif elem['type'] == 'bitfield32':        861         elif elem['type'] == 'bitfield32':
841             t = TypeBitfield32(self.family, se    862             t = TypeBitfield32(self.family, self, elem, value)
842         elif elem['type'] == 'nest':              863         elif elem['type'] == 'nest':
843             t = TypeNest(self.family, self, el    864             t = TypeNest(self.family, self, elem, value)
844         elif elem['type'] == 'indexed-array' a !! 865         elif elem['type'] == 'array-nest':
845             if elem["sub-type"] == 'nest':     !! 866             t = TypeArrayNest(self.family, self, elem, value)
846                 t = TypeArrayNest(self.family, << 
847             else:                              << 
848                 raise Exception(f'new_attr: un << 
849         elif elem['type'] == 'nest-type-value'    867         elif elem['type'] == 'nest-type-value':
850             t = TypeNestTypeValue(self.family,    868             t = TypeNestTypeValue(self.family, self, elem, value)
851         else:                                     869         else:
852             raise Exception(f"No typed class f    870             raise Exception(f"No typed class for type {elem['type']}")
853                                                   871 
854         if 'multi-attr' in elem and elem['mult    872         if 'multi-attr' in elem and elem['multi-attr']:
855             t = TypeMultiAttr(self.family, sel    873             t = TypeMultiAttr(self.family, self, elem, value, t)
856                                                   874 
857         return t                                  875         return t
858                                                   876 
859                                                   877 
860 class Operation(SpecOperation):                   878 class Operation(SpecOperation):
861     def __init__(self, family, yaml, req_value    879     def __init__(self, family, yaml, req_value, rsp_value):
862         super().__init__(family, yaml, req_val    880         super().__init__(family, yaml, req_value, rsp_value)
863                                                   881 
864         self.render_name = c_lower(family.iden !! 882         self.render_name = c_lower(family.name + '_' + self.name)
865                                                   883 
866         self.dual_policy = ('do' in yaml and '    884         self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \
867                          ('dump' in yaml and '    885                          ('dump' in yaml and 'request' in yaml['dump'])
868                                                   886 
869         self.has_ntf = False                      887         self.has_ntf = False
870                                                   888 
871         # Added by resolve:                       889         # Added by resolve:
872         self.enum_name = None                     890         self.enum_name = None
873         delattr(self, "enum_name")                891         delattr(self, "enum_name")
874                                                   892 
875     def resolve(self):                            893     def resolve(self):
876         self.resolve_up(super())                  894         self.resolve_up(super())
877                                                   895 
878         if not self.is_async:                     896         if not self.is_async:
879             self.enum_name = self.family.op_pr    897             self.enum_name = self.family.op_prefix + c_upper(self.name)
880         else:                                     898         else:
881             self.enum_name = self.family.async    899             self.enum_name = self.family.async_op_prefix + c_upper(self.name)
882                                                   900 
883     def mark_has_ntf(self):                       901     def mark_has_ntf(self):
884         self.has_ntf = True                       902         self.has_ntf = True
885                                                   903 
886                                                   904 
887 class Family(SpecFamily):                         905 class Family(SpecFamily):
888     def __init__(self, file_name, exclude_ops)    906     def __init__(self, file_name, exclude_ops):
889         # Added by resolve:                       907         # Added by resolve:
890         self.c_name = None                        908         self.c_name = None
891         delattr(self, "c_name")                   909         delattr(self, "c_name")
892         self.op_prefix = None                     910         self.op_prefix = None
893         delattr(self, "op_prefix")                911         delattr(self, "op_prefix")
894         self.async_op_prefix = None               912         self.async_op_prefix = None
895         delattr(self, "async_op_prefix")          913         delattr(self, "async_op_prefix")
896         self.mcgrps = None                        914         self.mcgrps = None
897         delattr(self, "mcgrps")                   915         delattr(self, "mcgrps")
898         self.consts = None                        916         self.consts = None
899         delattr(self, "consts")                   917         delattr(self, "consts")
900         self.hooks = None                         918         self.hooks = None
901         delattr(self, "hooks")                    919         delattr(self, "hooks")
902                                                   920 
903         super().__init__(file_name, exclude_op    921         super().__init__(file_name, exclude_ops=exclude_ops)
904                                                   922 
905         self.fam_key = c_upper(self.yaml.get('    923         self.fam_key = c_upper(self.yaml.get('c-family-name', self.yaml["name"] + '_FAMILY_NAME'))
906         self.ver_key = c_upper(self.yaml.get('    924         self.ver_key = c_upper(self.yaml.get('c-version-name', self.yaml["name"] + '_FAMILY_VERSION'))
907                                                   925 
908         if 'definitions' not in self.yaml:        926         if 'definitions' not in self.yaml:
909             self.yaml['definitions'] = []         927             self.yaml['definitions'] = []
910                                                   928 
911         if 'uapi-header' in self.yaml:            929         if 'uapi-header' in self.yaml:
912             self.uapi_header = self.yaml['uapi    930             self.uapi_header = self.yaml['uapi-header']
913         else:                                     931         else:
914             self.uapi_header = f"linux/{self.i !! 932             self.uapi_header = f"linux/{self.name}.h"
915         if self.uapi_header.startswith("linux/    933         if self.uapi_header.startswith("linux/") and self.uapi_header.endswith('.h'):
916             self.uapi_header_name = self.uapi_    934             self.uapi_header_name = self.uapi_header[6:-2]
917         else:                                     935         else:
918             self.uapi_header_name = self.ident !! 936             self.uapi_header_name = self.name
919                                                   937 
920     def resolve(self):                            938     def resolve(self):
921         self.resolve_up(super())                  939         self.resolve_up(super())
922                                                   940 
923         if self.yaml.get('protocol', 'genetlin    941         if self.yaml.get('protocol', 'genetlink') not in {'genetlink', 'genetlink-c', 'genetlink-legacy'}:
924             raise Exception("Codegen only supp    942             raise Exception("Codegen only supported for genetlink")
925                                                   943 
926         self.c_name = c_lower(self.ident_name) !! 944         self.c_name = c_lower(self.name)
927         if 'name-prefix' in self.yaml['operati    945         if 'name-prefix' in self.yaml['operations']:
928             self.op_prefix = c_upper(self.yaml    946             self.op_prefix = c_upper(self.yaml['operations']['name-prefix'])
929         else:                                     947         else:
930             self.op_prefix = c_upper(self.yaml    948             self.op_prefix = c_upper(self.yaml['name'] + '-cmd-')
931         if 'async-prefix' in self.yaml['operat    949         if 'async-prefix' in self.yaml['operations']:
932             self.async_op_prefix = c_upper(sel    950             self.async_op_prefix = c_upper(self.yaml['operations']['async-prefix'])
933         else:                                     951         else:
934             self.async_op_prefix = self.op_pre    952             self.async_op_prefix = self.op_prefix
935                                                   953 
936         self.mcgrps = self.yaml.get('mcast-gro    954         self.mcgrps = self.yaml.get('mcast-groups', {'list': []})
937                                                   955 
938         self.hooks = dict()                       956         self.hooks = dict()
939         for when in ['pre', 'post']:              957         for when in ['pre', 'post']:
940             self.hooks[when] = dict()             958             self.hooks[when] = dict()
941             for op_mode in ['do', 'dump']:        959             for op_mode in ['do', 'dump']:
942                 self.hooks[when][op_mode] = di    960                 self.hooks[when][op_mode] = dict()
943                 self.hooks[when][op_mode]['set    961                 self.hooks[when][op_mode]['set'] = set()
944                 self.hooks[when][op_mode]['lis    962                 self.hooks[when][op_mode]['list'] = []
945                                                   963 
946         # dict space-name -> 'request': set(at    964         # dict space-name -> 'request': set(attrs), 'reply': set(attrs)
947         self.root_sets = dict()                   965         self.root_sets = dict()
948         # dict space-name -> set('request', 'r    966         # dict space-name -> set('request', 'reply')
949         self.pure_nested_structs = dict()         967         self.pure_nested_structs = dict()
950                                                   968 
951         self._mark_notify()                       969         self._mark_notify()
952         self._mock_up_events()                    970         self._mock_up_events()
953                                                   971 
954         self._load_root_sets()                    972         self._load_root_sets()
955         self._load_nested_sets()                  973         self._load_nested_sets()
956         self._load_attr_use()                     974         self._load_attr_use()
957         self._load_hooks()                        975         self._load_hooks()
958                                                   976 
959         self.kernel_policy = self.yaml.get('ke    977         self.kernel_policy = self.yaml.get('kernel-policy', 'split')
960         if self.kernel_policy == 'global':        978         if self.kernel_policy == 'global':
961             self._load_global_policy()            979             self._load_global_policy()
962                                                   980 
963     def new_enum(self, elem):                     981     def new_enum(self, elem):
964         return EnumSet(self, elem)                982         return EnumSet(self, elem)
965                                                   983 
966     def new_attr_set(self, elem):                 984     def new_attr_set(self, elem):
967         return AttrSet(self, elem)                985         return AttrSet(self, elem)
968                                                   986 
969     def new_operation(self, elem, req_value, r    987     def new_operation(self, elem, req_value, rsp_value):
970         return Operation(self, elem, req_value    988         return Operation(self, elem, req_value, rsp_value)
971                                                   989 
972     def _mark_notify(self):                       990     def _mark_notify(self):
973         for op in self.msgs.values():             991         for op in self.msgs.values():
974             if 'notify' in op:                    992             if 'notify' in op:
975                 self.ops[op['notify']].mark_ha    993                 self.ops[op['notify']].mark_has_ntf()
976                                                   994 
977     # Fake a 'do' equivalent of all events, so    995     # Fake a 'do' equivalent of all events, so that we can render their response parsing
978     def _mock_up_events(self):                    996     def _mock_up_events(self):
979         for op in self.yaml['operations']['lis    997         for op in self.yaml['operations']['list']:
980             if 'event' in op:                     998             if 'event' in op:
981                 op['do'] = {                      999                 op['do'] = {
982                     'reply': {                    1000                     'reply': {
983                         'attributes': op['even    1001                         'attributes': op['event']['attributes']
984                     }                             1002                     }
985                 }                                 1003                 }
986                                                   1004 
987     def _load_root_sets(self):                    1005     def _load_root_sets(self):
988         for op_name, op in self.msgs.items():     1006         for op_name, op in self.msgs.items():
989             if 'attribute-set' not in op:         1007             if 'attribute-set' not in op:
990                 continue                          1008                 continue
991                                                   1009 
992             req_attrs = set()                     1010             req_attrs = set()
993             rsp_attrs = set()                     1011             rsp_attrs = set()
994             for op_mode in ['do', 'dump']:        1012             for op_mode in ['do', 'dump']:
995                 if op_mode in op and 'request'    1013                 if op_mode in op and 'request' in op[op_mode]:
996                     req_attrs.update(set(op[op    1014                     req_attrs.update(set(op[op_mode]['request']['attributes']))
997                 if op_mode in op and 'reply' i    1015                 if op_mode in op and 'reply' in op[op_mode]:
998                     rsp_attrs.update(set(op[op    1016                     rsp_attrs.update(set(op[op_mode]['reply']['attributes']))
999             if 'event' in op:                     1017             if 'event' in op:
1000                 rsp_attrs.update(set(op['even    1018                 rsp_attrs.update(set(op['event']['attributes']))
1001                                                  1019 
1002             if op['attribute-set'] not in sel    1020             if op['attribute-set'] not in self.root_sets:
1003                 self.root_sets[op['attribute-    1021                 self.root_sets[op['attribute-set']] = {'request': req_attrs, 'reply': rsp_attrs}
1004             else:                                1022             else:
1005                 self.root_sets[op['attribute-    1023                 self.root_sets[op['attribute-set']]['request'].update(req_attrs)
1006                 self.root_sets[op['attribute-    1024                 self.root_sets[op['attribute-set']]['reply'].update(rsp_attrs)
1007                                                  1025 
1008     def _sort_pure_types(self):                  1026     def _sort_pure_types(self):
1009         # Try to reorder according to depende    1027         # Try to reorder according to dependencies
1010         pns_key_list = list(self.pure_nested_    1028         pns_key_list = list(self.pure_nested_structs.keys())
1011         pns_key_seen = set()                     1029         pns_key_seen = set()
1012         rounds = len(pns_key_list) ** 2  # it    1030         rounds = len(pns_key_list) ** 2  # it's basically bubble sort
1013         for _ in range(rounds):                  1031         for _ in range(rounds):
1014             if len(pns_key_list) == 0:           1032             if len(pns_key_list) == 0:
1015                 break                            1033                 break
1016             name = pns_key_list.pop(0)           1034             name = pns_key_list.pop(0)
1017             finished = True                      1035             finished = True
1018             for _, spec in self.attr_sets[nam    1036             for _, spec in self.attr_sets[name].items():
1019                 if 'nested-attributes' in spe    1037                 if 'nested-attributes' in spec:
1020                     nested = spec['nested-att    1038                     nested = spec['nested-attributes']
1021                     # If the unknown nest we     1039                     # If the unknown nest we hit is recursive it's fine, it'll be a pointer
1022                     if self.pure_nested_struc    1040                     if self.pure_nested_structs[nested].recursive:
1023                         continue                 1041                         continue
1024                     if nested not in pns_key_    1042                     if nested not in pns_key_seen:
1025                         # Dicts are sorted, t    1043                         # Dicts are sorted, this will make struct last
1026                         struct = self.pure_ne    1044                         struct = self.pure_nested_structs.pop(name)
1027                         self.pure_nested_stru    1045                         self.pure_nested_structs[name] = struct
1028                         finished = False         1046                         finished = False
1029                         break                    1047                         break
1030             if finished:                         1048             if finished:
1031                 pns_key_seen.add(name)           1049                 pns_key_seen.add(name)
1032             else:                                1050             else:
1033                 pns_key_list.append(name)        1051                 pns_key_list.append(name)
1034                                                  1052 
1035     def _load_nested_sets(self):                 1053     def _load_nested_sets(self):
1036         attr_set_queue = list(self.root_sets.    1054         attr_set_queue = list(self.root_sets.keys())
1037         attr_set_seen = set(self.root_sets.ke    1055         attr_set_seen = set(self.root_sets.keys())
1038                                                  1056 
1039         while len(attr_set_queue):               1057         while len(attr_set_queue):
1040             a_set = attr_set_queue.pop(0)        1058             a_set = attr_set_queue.pop(0)
1041             for attr, spec in self.attr_sets[    1059             for attr, spec in self.attr_sets[a_set].items():
1042                 if 'nested-attributes' not in    1060                 if 'nested-attributes' not in spec:
1043                     continue                     1061                     continue
1044                                                  1062 
1045                 nested = spec['nested-attribu    1063                 nested = spec['nested-attributes']
1046                 if nested not in attr_set_see    1064                 if nested not in attr_set_seen:
1047                     attr_set_queue.append(nes    1065                     attr_set_queue.append(nested)
1048                     attr_set_seen.add(nested)    1066                     attr_set_seen.add(nested)
1049                                                  1067 
1050                 inherit = set()                  1068                 inherit = set()
1051                 if nested not in self.root_se    1069                 if nested not in self.root_sets:
1052                     if nested not in self.pur    1070                     if nested not in self.pure_nested_structs:
1053                         self.pure_nested_stru    1071                         self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit)
1054                 else:                            1072                 else:
1055                     raise Exception(f'Using a    1073                     raise Exception(f'Using attr set as root and nested not supported - {nested}')
1056                                                  1074 
1057                 if 'type-value' in spec:         1075                 if 'type-value' in spec:
1058                     if nested in self.root_se    1076                     if nested in self.root_sets:
1059                         raise Exception("Inhe    1077                         raise Exception("Inheriting members to a space used as root not supported")
1060                     inherit.update(set(spec['    1078                     inherit.update(set(spec['type-value']))
1061                 elif spec['type'] == 'indexed !! 1079                 elif spec['type'] == 'array-nest':
1062                     inherit.add('idx')           1080                     inherit.add('idx')
1063                 self.pure_nested_structs[nest    1081                 self.pure_nested_structs[nested].set_inherited(inherit)
1064                                                  1082 
1065         for root_set, rs_members in self.root    1083         for root_set, rs_members in self.root_sets.items():
1066             for attr, spec in self.attr_sets[    1084             for attr, spec in self.attr_sets[root_set].items():
1067                 if 'nested-attributes' in spe    1085                 if 'nested-attributes' in spec:
1068                     nested = spec['nested-att    1086                     nested = spec['nested-attributes']
1069                     if attr in rs_members['re    1087                     if attr in rs_members['request']:
1070                         self.pure_nested_stru    1088                         self.pure_nested_structs[nested].request = True
1071                     if attr in rs_members['re    1089                     if attr in rs_members['reply']:
1072                         self.pure_nested_stru    1090                         self.pure_nested_structs[nested].reply = True
1073                                                  1091 
1074         self._sort_pure_types()                  1092         self._sort_pure_types()
1075                                                  1093 
1076         # Propagate the request / reply / rec    1094         # Propagate the request / reply / recursive
1077         for attr_set, struct in reversed(self    1095         for attr_set, struct in reversed(self.pure_nested_structs.items()):
1078             for _, spec in self.attr_sets[att    1096             for _, spec in self.attr_sets[attr_set].items():
1079                 if 'nested-attributes' in spe    1097                 if 'nested-attributes' in spec:
1080                     child_name = spec['nested    1098                     child_name = spec['nested-attributes']
1081                     struct.child_nests.add(ch    1099                     struct.child_nests.add(child_name)
1082                     child = self.pure_nested_    1100                     child = self.pure_nested_structs.get(child_name)
1083                     if child:                    1101                     if child:
1084                         if not child.recursiv    1102                         if not child.recursive:
1085                             struct.child_nest    1103                             struct.child_nests.update(child.child_nests)
1086                         child.request |= stru    1104                         child.request |= struct.request
1087                         child.reply |= struct    1105                         child.reply |= struct.reply
1088                 if attr_set in struct.child_n    1106                 if attr_set in struct.child_nests:
1089                     struct.recursive = True      1107                     struct.recursive = True
1090                                                  1108 
1091         self._sort_pure_types()                  1109         self._sort_pure_types()
1092                                                  1110 
1093     def _load_attr_use(self):                    1111     def _load_attr_use(self):
1094         for _, struct in self.pure_nested_str    1112         for _, struct in self.pure_nested_structs.items():
1095             if struct.request:                   1113             if struct.request:
1096                 for _, arg in struct.member_l    1114                 for _, arg in struct.member_list():
1097                     arg.request = True           1115                     arg.request = True
1098             if struct.reply:                     1116             if struct.reply:
1099                 for _, arg in struct.member_l    1117                 for _, arg in struct.member_list():
1100                     arg.reply = True             1118                     arg.reply = True
1101                                                  1119 
1102         for root_set, rs_members in self.root    1120         for root_set, rs_members in self.root_sets.items():
1103             for attr, spec in self.attr_sets[    1121             for attr, spec in self.attr_sets[root_set].items():
1104                 if attr in rs_members['reques    1122                 if attr in rs_members['request']:
1105                     spec.request = True          1123                     spec.request = True
1106                 if attr in rs_members['reply'    1124                 if attr in rs_members['reply']:
1107                     spec.reply = True            1125                     spec.reply = True
1108                                                  1126 
1109     def _load_global_policy(self):               1127     def _load_global_policy(self):
1110         global_set = set()                       1128         global_set = set()
1111         attr_set_name = None                     1129         attr_set_name = None
1112         for op_name, op in self.ops.items():     1130         for op_name, op in self.ops.items():
1113             if not op:                           1131             if not op:
1114                 continue                         1132                 continue
1115             if 'attribute-set' not in op:        1133             if 'attribute-set' not in op:
1116                 continue                         1134                 continue
1117                                                  1135 
1118             if attr_set_name is None:            1136             if attr_set_name is None:
1119                 attr_set_name = op['attribute    1137                 attr_set_name = op['attribute-set']
1120             if attr_set_name != op['attribute    1138             if attr_set_name != op['attribute-set']:
1121                 raise Exception('For a global    1139                 raise Exception('For a global policy all ops must use the same set')
1122                                                  1140 
1123             for op_mode in ['do', 'dump']:       1141             for op_mode in ['do', 'dump']:
1124                 if op_mode in op:                1142                 if op_mode in op:
1125                     req = op[op_mode].get('re    1143                     req = op[op_mode].get('request')
1126                     if req:                      1144                     if req:
1127                         global_set.update(req    1145                         global_set.update(req.get('attributes', []))
1128                                                  1146 
1129         self.global_policy = []                  1147         self.global_policy = []
1130         self.global_policy_set = attr_set_nam    1148         self.global_policy_set = attr_set_name
1131         for attr in self.attr_sets[attr_set_n    1149         for attr in self.attr_sets[attr_set_name]:
1132             if attr in global_set:               1150             if attr in global_set:
1133                 self.global_policy.append(att    1151                 self.global_policy.append(attr)
1134                                                  1152 
1135     def _load_hooks(self):                       1153     def _load_hooks(self):
1136         for op in self.ops.values():             1154         for op in self.ops.values():
1137             for op_mode in ['do', 'dump']:       1155             for op_mode in ['do', 'dump']:
1138                 if op_mode not in op:            1156                 if op_mode not in op:
1139                     continue                     1157                     continue
1140                 for when in ['pre', 'post']:     1158                 for when in ['pre', 'post']:
1141                     if when not in op[op_mode    1159                     if when not in op[op_mode]:
1142                         continue                 1160                         continue
1143                     name = op[op_mode][when]     1161                     name = op[op_mode][when]
1144                     if name in self.hooks[whe    1162                     if name in self.hooks[when][op_mode]['set']:
1145                         continue                 1163                         continue
1146                     self.hooks[when][op_mode]    1164                     self.hooks[when][op_mode]['set'].add(name)
1147                     self.hooks[when][op_mode]    1165                     self.hooks[when][op_mode]['list'].append(name)
1148                                                  1166 
1149                                                  1167 
1150 class RenderInfo:                                1168 class RenderInfo:
1151     def __init__(self, cw, family, ku_space,     1169     def __init__(self, cw, family, ku_space, op, op_mode, attr_set=None):
1152         self.family = family                     1170         self.family = family
1153         self.nl = cw.nlib                        1171         self.nl = cw.nlib
1154         self.ku_space = ku_space                 1172         self.ku_space = ku_space
1155         self.op_mode = op_mode                   1173         self.op_mode = op_mode
1156         self.op = op                             1174         self.op = op
1157                                                  1175 
1158         self.fixed_hdr = None                    1176         self.fixed_hdr = None
1159         if op and op.fixed_header:               1177         if op and op.fixed_header:
1160             self.fixed_hdr = 'struct ' + c_lo    1178             self.fixed_hdr = 'struct ' + c_lower(op.fixed_header)
1161                                                  1179 
1162         # 'do' and 'dump' response parsing is    1180         # 'do' and 'dump' response parsing is identical
1163         self.type_consistent = True              1181         self.type_consistent = True
1164         if op_mode != 'do' and 'dump' in op:     1182         if op_mode != 'do' and 'dump' in op:
1165             if 'do' in op:                       1183             if 'do' in op:
1166                 if ('reply' in op['do']) != (    1184                 if ('reply' in op['do']) != ('reply' in op["dump"]):
1167                     self.type_consistent = Fa    1185                     self.type_consistent = False
1168                 elif 'reply' in op['do'] and     1186                 elif 'reply' in op['do'] and op["do"]["reply"] != op["dump"]["reply"]:
1169                     self.type_consistent = Fa    1187                     self.type_consistent = False
1170             else:                                1188             else:
1171                 self.type_consistent = False     1189                 self.type_consistent = False
1172                                                  1190 
1173         self.attr_set = attr_set                 1191         self.attr_set = attr_set
1174         if not self.attr_set:                    1192         if not self.attr_set:
1175             self.attr_set = op['attribute-set    1193             self.attr_set = op['attribute-set']
1176                                                  1194 
1177         self.type_name_conflict = False          1195         self.type_name_conflict = False
1178         if op:                                   1196         if op:
1179             self.type_name = c_lower(op.name)    1197             self.type_name = c_lower(op.name)
1180         else:                                    1198         else:
1181             self.type_name = c_lower(attr_set    1199             self.type_name = c_lower(attr_set)
1182             if attr_set in family.consts:        1200             if attr_set in family.consts:
1183                 self.type_name_conflict = Tru    1201                 self.type_name_conflict = True
1184                                                  1202 
1185         self.cw = cw                             1203         self.cw = cw
1186                                                  1204 
1187         self.struct = dict()                     1205         self.struct = dict()
1188         if op_mode == 'notify':                  1206         if op_mode == 'notify':
1189             op_mode = 'do'                       1207             op_mode = 'do'
1190         for op_dir in ['request', 'reply']:      1208         for op_dir in ['request', 'reply']:
1191             if op:                               1209             if op:
1192                 type_list = []                   1210                 type_list = []
1193                 if op_dir in op[op_mode]:        1211                 if op_dir in op[op_mode]:
1194                     type_list = op[op_mode][o    1212                     type_list = op[op_mode][op_dir]['attributes']
1195                 self.struct[op_dir] = Struct(    1213                 self.struct[op_dir] = Struct(family, self.attr_set, type_list=type_list)
1196         if op_mode == 'event':                   1214         if op_mode == 'event':
1197             self.struct['reply'] = Struct(fam    1215             self.struct['reply'] = Struct(family, self.attr_set, type_list=op['event']['attributes'])
1198                                                  1216 
1199                                                  1217 
1200 class CodeWriter:                                1218 class CodeWriter:
1201     def __init__(self, nlib, out_file=None, o    1219     def __init__(self, nlib, out_file=None, overwrite=True):
1202         self.nlib = nlib                         1220         self.nlib = nlib
1203         self._overwrite = overwrite              1221         self._overwrite = overwrite
1204                                                  1222 
1205         self._nl = False                         1223         self._nl = False
1206         self._block_end = False                  1224         self._block_end = False
1207         self._silent_block = False               1225         self._silent_block = False
1208         self._ind = 0                            1226         self._ind = 0
1209         self._ifdef_block = None                 1227         self._ifdef_block = None
1210         if out_file is None:                     1228         if out_file is None:
1211             self._out = os.sys.stdout            1229             self._out = os.sys.stdout
1212         else:                                    1230         else:
1213             self._out = tempfile.NamedTempora    1231             self._out = tempfile.NamedTemporaryFile('w+')
1214             self._out_file = out_file            1232             self._out_file = out_file
1215                                                  1233 
1216     def __del__(self):                           1234     def __del__(self):
1217         self.close_out_file()                    1235         self.close_out_file()
1218                                                  1236 
1219     def close_out_file(self):                    1237     def close_out_file(self):
1220         if self._out == os.sys.stdout:           1238         if self._out == os.sys.stdout:
1221             return                               1239             return
1222         # Avoid modifying the file if content    1240         # Avoid modifying the file if contents didn't change
1223         self._out.flush()                        1241         self._out.flush()
1224         if not self._overwrite and os.path.is    1242         if not self._overwrite and os.path.isfile(self._out_file):
1225             if filecmp.cmp(self._out.name, se    1243             if filecmp.cmp(self._out.name, self._out_file, shallow=False):
1226                 return                           1244                 return
1227         with open(self._out_file, 'w+') as ou    1245         with open(self._out_file, 'w+') as out_file:
1228             self._out.seek(0)                    1246             self._out.seek(0)
1229             shutil.copyfileobj(self._out, out    1247             shutil.copyfileobj(self._out, out_file)
1230             self._out.close()                    1248             self._out.close()
1231         self._out = os.sys.stdout                1249         self._out = os.sys.stdout
1232                                                  1250 
1233     @classmethod                                 1251     @classmethod
1234     def _is_cond(cls, line):                     1252     def _is_cond(cls, line):
1235         return line.startswith('if') or line.    1253         return line.startswith('if') or line.startswith('while') or line.startswith('for')
1236                                                  1254 
1237     def p(self, line, add_ind=0):                1255     def p(self, line, add_ind=0):
1238         if self._block_end:                      1256         if self._block_end:
1239             self._block_end = False              1257             self._block_end = False
1240             if line.startswith('else'):          1258             if line.startswith('else'):
1241                 line = '} ' + line               1259                 line = '} ' + line
1242             else:                                1260             else:
1243                 self._out.write('\t' * self._    1261                 self._out.write('\t' * self._ind + '}\n')
1244                                                  1262 
1245         if self._nl:                             1263         if self._nl:
1246             self._out.write('\n')                1264             self._out.write('\n')
1247             self._nl = False                     1265             self._nl = False
1248                                                  1266 
1249         ind = self._ind                          1267         ind = self._ind
1250         if line[-1] == ':':                      1268         if line[-1] == ':':
1251             ind -= 1                             1269             ind -= 1
1252         if self._silent_block:                   1270         if self._silent_block:
1253             ind += 1                             1271             ind += 1
1254         self._silent_block = line.endswith(')    1272         self._silent_block = line.endswith(')') and CodeWriter._is_cond(line)
1255         if line[0] == '#':                       1273         if line[0] == '#':
1256             ind = 0                              1274             ind = 0
1257         if add_ind:                              1275         if add_ind:
1258             ind += add_ind                       1276             ind += add_ind
1259         self._out.write('\t' * ind + line + '    1277         self._out.write('\t' * ind + line + '\n')
1260                                                  1278 
1261     def nl(self):                                1279     def nl(self):
1262         self._nl = True                          1280         self._nl = True
1263                                                  1281 
1264     def block_start(self, line=''):              1282     def block_start(self, line=''):
1265         if line:                                 1283         if line:
1266             line = line + ' '                    1284             line = line + ' '
1267         self.p(line + '{')                       1285         self.p(line + '{')
1268         self._ind += 1                           1286         self._ind += 1
1269                                                  1287 
1270     def block_end(self, line=''):                1288     def block_end(self, line=''):
1271         if line and line[0] not in {';', ','}    1289         if line and line[0] not in {';', ','}:
1272             line = ' ' + line                    1290             line = ' ' + line
1273         self._ind -= 1                           1291         self._ind -= 1
1274         self._nl = False                         1292         self._nl = False
1275         if not line:                             1293         if not line:
1276             # Delay printing closing bracket     1294             # Delay printing closing bracket in case "else" comes next
1277             if self._block_end:                  1295             if self._block_end:
1278                 self._out.write('\t' * (self.    1296                 self._out.write('\t' * (self._ind + 1) + '}\n')
1279             self._block_end = True               1297             self._block_end = True
1280         else:                                    1298         else:
1281             self.p('}' + line)                   1299             self.p('}' + line)
1282                                                  1300 
1283     def write_doc_line(self, doc, indent=True    1301     def write_doc_line(self, doc, indent=True):
1284         words = doc.split()                      1302         words = doc.split()
1285         line = ' *'                              1303         line = ' *'
1286         for word in words:                       1304         for word in words:
1287             if len(line) + len(word) >= 79:      1305             if len(line) + len(word) >= 79:
1288                 self.p(line)                     1306                 self.p(line)
1289                 line = ' *'                      1307                 line = ' *'
1290                 if indent:                       1308                 if indent:
1291                     line += '  '                 1309                     line += '  '
1292             line += ' ' + word                   1310             line += ' ' + word
1293         self.p(line)                             1311         self.p(line)
1294                                                  1312 
1295     def write_func_prot(self, qual_ret, name,    1313     def write_func_prot(self, qual_ret, name, args=None, doc=None, suffix=''):
1296         if not args:                             1314         if not args:
1297             args = ['void']                      1315             args = ['void']
1298                                                  1316 
1299         if doc:                                  1317         if doc:
1300             self.p('/*')                         1318             self.p('/*')
1301             self.p(' * ' + doc)                  1319             self.p(' * ' + doc)
1302             self.p(' */')                        1320             self.p(' */')
1303                                                  1321 
1304         oneline = qual_ret                       1322         oneline = qual_ret
1305         if qual_ret[-1] != '*':                  1323         if qual_ret[-1] != '*':
1306             oneline += ' '                       1324             oneline += ' '
1307         oneline += f"{name}({', '.join(args)}    1325         oneline += f"{name}({', '.join(args)}){suffix}"
1308                                                  1326 
1309         if len(oneline) < 80:                    1327         if len(oneline) < 80:
1310             self.p(oneline)                      1328             self.p(oneline)
1311             return                               1329             return
1312                                                  1330 
1313         v = qual_ret                             1331         v = qual_ret
1314         if len(v) > 3:                           1332         if len(v) > 3:
1315             self.p(v)                            1333             self.p(v)
1316             v = ''                               1334             v = ''
1317         elif qual_ret[-1] != '*':                1335         elif qual_ret[-1] != '*':
1318             v += ' '                             1336             v += ' '
1319         v += name + '('                          1337         v += name + '('
1320         ind = '\t' * (len(v) // 8) + ' ' * (l    1338         ind = '\t' * (len(v) // 8) + ' ' * (len(v) % 8)
1321         delta_ind = len(v) - len(ind)            1339         delta_ind = len(v) - len(ind)
1322         v += args[0]                             1340         v += args[0]
1323         i = 1                                    1341         i = 1
1324         while i < len(args):                     1342         while i < len(args):
1325             next_len = len(v) + len(args[i])     1343             next_len = len(v) + len(args[i])
1326             if v[0] == '\t':                     1344             if v[0] == '\t':
1327                 next_len += delta_ind            1345                 next_len += delta_ind
1328             if next_len > 76:                    1346             if next_len > 76:
1329                 self.p(v + ',')                  1347                 self.p(v + ',')
1330                 v = ind                          1348                 v = ind
1331             else:                                1349             else:
1332                 v += ', '                        1350                 v += ', '
1333             v += args[i]                         1351             v += args[i]
1334             i += 1                               1352             i += 1
1335         self.p(v + ')' + suffix)                 1353         self.p(v + ')' + suffix)
1336                                                  1354 
1337     def write_func_lvar(self, local_vars):       1355     def write_func_lvar(self, local_vars):
1338         if not local_vars:                       1356         if not local_vars:
1339             return                               1357             return
1340                                                  1358 
1341         if type(local_vars) is str:              1359         if type(local_vars) is str:
1342             local_vars = [local_vars]            1360             local_vars = [local_vars]
1343                                                  1361 
1344         local_vars.sort(key=len, reverse=True    1362         local_vars.sort(key=len, reverse=True)
1345         for var in local_vars:                   1363         for var in local_vars:
1346             self.p(var)                          1364             self.p(var)
1347         self.nl()                                1365         self.nl()
1348                                                  1366 
1349     def write_func(self, qual_ret, name, body    1367     def write_func(self, qual_ret, name, body, args=None, local_vars=None):
1350         self.write_func_prot(qual_ret=qual_re    1368         self.write_func_prot(qual_ret=qual_ret, name=name, args=args)
1351         self.write_func_lvar(local_vars=local    1369         self.write_func_lvar(local_vars=local_vars)
1352                                                  1370 
1353         self.block_start()                       1371         self.block_start()
1354         for line in body:                        1372         for line in body:
1355             self.p(line)                         1373             self.p(line)
1356         self.block_end()                         1374         self.block_end()
1357                                                  1375 
1358     def writes_defines(self, defines):           1376     def writes_defines(self, defines):
1359         longest = 0                              1377         longest = 0
1360         for define in defines:                   1378         for define in defines:
1361             if len(define[0]) > longest:         1379             if len(define[0]) > longest:
1362                 longest = len(define[0])         1380                 longest = len(define[0])
1363         longest = ((longest + 8) // 8) * 8       1381         longest = ((longest + 8) // 8) * 8
1364         for define in defines:                   1382         for define in defines:
1365             line = '#define ' + define[0]        1383             line = '#define ' + define[0]
1366             line += '\t' * ((longest - len(de    1384             line += '\t' * ((longest - len(define[0]) + 7) // 8)
1367             if type(define[1]) is int:           1385             if type(define[1]) is int:
1368                 line += str(define[1])           1386                 line += str(define[1])
1369             elif type(define[1]) is str:         1387             elif type(define[1]) is str:
1370                 line += '"' + define[1] + '"'    1388                 line += '"' + define[1] + '"'
1371             self.p(line)                         1389             self.p(line)
1372                                                  1390 
1373     def write_struct_init(self, members):        1391     def write_struct_init(self, members):
1374         longest = max([len(x[0]) for x in mem    1392         longest = max([len(x[0]) for x in members])
1375         longest += 1  # because we prepend a     1393         longest += 1  # because we prepend a .
1376         longest = ((longest + 8) // 8) * 8       1394         longest = ((longest + 8) // 8) * 8
1377         for one in members:                      1395         for one in members:
1378             line = '.' + one[0]                  1396             line = '.' + one[0]
1379             line += '\t' * ((longest - len(on    1397             line += '\t' * ((longest - len(one[0]) - 1 + 7) // 8)
1380             line += '= ' + str(one[1]) + ','     1398             line += '= ' + str(one[1]) + ','
1381             self.p(line)                         1399             self.p(line)
1382                                                  1400 
1383     def ifdef_block(self, config):               1401     def ifdef_block(self, config):
1384         config_option = None                     1402         config_option = None
1385         if config:                               1403         if config:
1386             config_option = 'CONFIG_' + c_upp    1404             config_option = 'CONFIG_' + c_upper(config)
1387         if self._ifdef_block == config_option    1405         if self._ifdef_block == config_option:
1388             return                               1406             return
1389                                                  1407 
1390         if self._ifdef_block:                    1408         if self._ifdef_block:
1391             self.p('#endif /* ' + self._ifdef    1409             self.p('#endif /* ' + self._ifdef_block + ' */')
1392         if config_option:                        1410         if config_option:
1393             self.p('#ifdef ' + config_option)    1411             self.p('#ifdef ' + config_option)
1394         self._ifdef_block = config_option        1412         self._ifdef_block = config_option
1395                                                  1413 
1396                                                  1414 
1397 scalars = {'u8', 'u16', 'u32', 'u64', 's32',     1415 scalars = {'u8', 'u16', 'u32', 'u64', 's32', 's64', 'uint', 'sint'}
1398                                                  1416 
1399 direction_to_suffix = {                          1417 direction_to_suffix = {
1400     'reply': '_rsp',                             1418     'reply': '_rsp',
1401     'request': '_req',                           1419     'request': '_req',
1402     '': ''                                       1420     '': ''
1403 }                                                1421 }
1404                                                  1422 
1405 op_mode_to_wrapper = {                           1423 op_mode_to_wrapper = {
1406     'do': '',                                    1424     'do': '',
1407     'dump': '_list',                             1425     'dump': '_list',
1408     'notify': '_ntf',                            1426     'notify': '_ntf',
1409     'event': '',                                 1427     'event': '',
1410 }                                                1428 }
1411                                                  1429 
1412 _C_KW = {                                        1430 _C_KW = {
1413     'auto',                                      1431     'auto',
1414     'bool',                                      1432     'bool',
1415     'break',                                     1433     'break',
1416     'case',                                      1434     'case',
1417     'char',                                      1435     'char',
1418     'const',                                     1436     'const',
1419     'continue',                                  1437     'continue',
1420     'default',                                   1438     'default',
1421     'do',                                        1439     'do',
1422     'double',                                    1440     'double',
1423     'else',                                      1441     'else',
1424     'enum',                                      1442     'enum',
1425     'extern',                                    1443     'extern',
1426     'float',                                     1444     'float',
1427     'for',                                       1445     'for',
1428     'goto',                                      1446     'goto',
1429     'if',                                        1447     'if',
1430     'inline',                                    1448     'inline',
1431     'int',                                       1449     'int',
1432     'long',                                      1450     'long',
1433     'register',                                  1451     'register',
1434     'return',                                    1452     'return',
1435     'short',                                     1453     'short',
1436     'signed',                                    1454     'signed',
1437     'sizeof',                                    1455     'sizeof',
1438     'static',                                    1456     'static',
1439     'struct',                                    1457     'struct',
1440     'switch',                                    1458     'switch',
1441     'typedef',                                   1459     'typedef',
1442     'union',                                     1460     'union',
1443     'unsigned',                                  1461     'unsigned',
1444     'void',                                      1462     'void',
1445     'volatile',                                  1463     'volatile',
1446     'while'                                      1464     'while'
1447 }                                                1465 }
1448                                                  1466 
1449                                                  1467 
1450 def rdir(direction):                             1468 def rdir(direction):
1451     if direction == 'reply':                     1469     if direction == 'reply':
1452         return 'request'                         1470         return 'request'
1453     if direction == 'request':                   1471     if direction == 'request':
1454         return 'reply'                           1472         return 'reply'
1455     return direction                             1473     return direction
1456                                                  1474 
1457                                                  1475 
1458 def op_prefix(ri, direction, deref=False):       1476 def op_prefix(ri, direction, deref=False):
1459     suffix = f"_{ri.type_name}"                  1477     suffix = f"_{ri.type_name}"
1460                                                  1478 
1461     if not ri.op_mode or ri.op_mode == 'do':     1479     if not ri.op_mode or ri.op_mode == 'do':
1462         suffix += f"{direction_to_suffix[dire    1480         suffix += f"{direction_to_suffix[direction]}"
1463     else:                                        1481     else:
1464         if direction == 'request':               1482         if direction == 'request':
1465             suffix += '_req_dump'                1483             suffix += '_req_dump'
1466         else:                                    1484         else:
1467             if ri.type_consistent:               1485             if ri.type_consistent:
1468                 if deref:                        1486                 if deref:
1469                     suffix += f"{direction_to    1487                     suffix += f"{direction_to_suffix[direction]}"
1470                 else:                            1488                 else:
1471                     suffix += op_mode_to_wrap    1489                     suffix += op_mode_to_wrapper[ri.op_mode]
1472             else:                                1490             else:
1473                 suffix += '_rsp'                 1491                 suffix += '_rsp'
1474                 suffix += '_dump' if deref el    1492                 suffix += '_dump' if deref else '_list'
1475                                                  1493 
1476     return f"{ri.family.c_name}{suffix}"         1494     return f"{ri.family.c_name}{suffix}"
1477                                                  1495 
1478                                                  1496 
1479 def type_name(ri, direction, deref=False):       1497 def type_name(ri, direction, deref=False):
1480     return f"struct {op_prefix(ri, direction,    1498     return f"struct {op_prefix(ri, direction, deref=deref)}"
1481                                                  1499 
1482                                                  1500 
1483 def print_prototype(ri, direction, terminate=    1501 def print_prototype(ri, direction, terminate=True, doc=None):
1484     suffix = ';' if terminate else ''            1502     suffix = ';' if terminate else ''
1485                                                  1503 
1486     fname = ri.op.render_name                    1504     fname = ri.op.render_name
1487     if ri.op_mode == 'dump':                     1505     if ri.op_mode == 'dump':
1488         fname += '_dump'                         1506         fname += '_dump'
1489                                                  1507 
1490     args = ['struct ynl_sock *ys']               1508     args = ['struct ynl_sock *ys']
1491     if 'request' in ri.op[ri.op_mode]:           1509     if 'request' in ri.op[ri.op_mode]:
1492         args.append(f"{type_name(ri, directio    1510         args.append(f"{type_name(ri, direction)} *" + f"{direction_to_suffix[direction][1:]}")
1493                                                  1511 
1494     ret = 'int'                                  1512     ret = 'int'
1495     if 'reply' in ri.op[ri.op_mode]:             1513     if 'reply' in ri.op[ri.op_mode]:
1496         ret = f"{type_name(ri, rdir(direction    1514         ret = f"{type_name(ri, rdir(direction))} *"
1497                                                  1515 
1498     ri.cw.write_func_prot(ret, fname, args, d    1516     ri.cw.write_func_prot(ret, fname, args, doc=doc, suffix=suffix)
1499                                                  1517 
1500                                                  1518 
1501 def print_req_prototype(ri):                     1519 def print_req_prototype(ri):
1502     print_prototype(ri, "request", doc=ri.op[    1520     print_prototype(ri, "request", doc=ri.op['doc'])
1503                                                  1521 
1504                                                  1522 
1505 def print_dump_prototype(ri):                    1523 def print_dump_prototype(ri):
1506     print_prototype(ri, "request")               1524     print_prototype(ri, "request")
1507                                                  1525 
1508                                                  1526 
1509 def put_typol_fwd(cw, struct):                   1527 def put_typol_fwd(cw, struct):
1510     cw.p(f'extern const struct ynl_policy_nes !! 1528     cw.p(f'extern struct ynl_policy_nest {struct.render_name}_nest;')
1511                                                  1529 
1512                                                  1530 
1513 def put_typol(cw, struct):                       1531 def put_typol(cw, struct):
1514     type_max = struct.attr_set.max_name          1532     type_max = struct.attr_set.max_name
1515     cw.block_start(line=f'const struct ynl_po !! 1533     cw.block_start(line=f'struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =')
1516                                                  1534 
1517     for _, arg in struct.member_list():          1535     for _, arg in struct.member_list():
1518         arg.attr_typol(cw)                       1536         arg.attr_typol(cw)
1519                                                  1537 
1520     cw.block_end(line=';')                       1538     cw.block_end(line=';')
1521     cw.nl()                                      1539     cw.nl()
1522                                                  1540 
1523     cw.block_start(line=f'const struct ynl_po !! 1541     cw.block_start(line=f'struct ynl_policy_nest {struct.render_name}_nest =')
1524     cw.p(f'.max_attr = {type_max},')             1542     cw.p(f'.max_attr = {type_max},')
1525     cw.p(f'.table = {struct.render_name}_poli    1543     cw.p(f'.table = {struct.render_name}_policy,')
1526     cw.block_end(line=';')                       1544     cw.block_end(line=';')
1527     cw.nl()                                      1545     cw.nl()
1528                                                  1546 
1529                                                  1547 
1530 def _put_enum_to_str_helper(cw, render_name,     1548 def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None):
1531     args = [f'int {arg_name}']                   1549     args = [f'int {arg_name}']
1532     if enum:                                     1550     if enum:
1533         args = [enum.user_type + ' ' + arg_na    1551         args = [enum.user_type + ' ' + arg_name]
1534     cw.write_func_prot('const char *', f'{ren    1552     cw.write_func_prot('const char *', f'{render_name}_str', args)
1535     cw.block_start()                             1553     cw.block_start()
1536     if enum and enum.type == 'flags':            1554     if enum and enum.type == 'flags':
1537         cw.p(f'{arg_name} = ffs({arg_name}) -    1555         cw.p(f'{arg_name} = ffs({arg_name}) - 1;')
1538     cw.p(f'if ({arg_name} < 0 || {arg_name} > !! 1556     cw.p(f'if ({arg_name} < 0 || {arg_name} >= (int)MNL_ARRAY_SIZE({map_name}))')
1539     cw.p('return NULL;')                         1557     cw.p('return NULL;')
1540     cw.p(f'return {map_name}[{arg_name}];')      1558     cw.p(f'return {map_name}[{arg_name}];')
1541     cw.block_end()                               1559     cw.block_end()
1542     cw.nl()                                      1560     cw.nl()
1543                                                  1561 
1544                                                  1562 
1545 def put_op_name_fwd(family, cw):                 1563 def put_op_name_fwd(family, cw):
1546     cw.write_func_prot('const char *', f'{fam    1564     cw.write_func_prot('const char *', f'{family.c_name}_op_str', ['int op'], suffix=';')
1547                                                  1565 
1548                                                  1566 
1549 def put_op_name(family, cw):                     1567 def put_op_name(family, cw):
1550     map_name = f'{family.c_name}_op_strmap'      1568     map_name = f'{family.c_name}_op_strmap'
1551     cw.block_start(line=f"static const char *    1569     cw.block_start(line=f"static const char * const {map_name}[] =")
1552     for op_name, op in family.msgs.items():      1570     for op_name, op in family.msgs.items():
1553         if op.rsp_value:                         1571         if op.rsp_value:
1554             # Make sure we don't add duplicat    1572             # Make sure we don't add duplicated entries, if multiple commands
1555             # produce the same response in le    1573             # produce the same response in legacy families.
1556             if family.rsp_by_value[op.rsp_val    1574             if family.rsp_by_value[op.rsp_value] != op:
1557                 cw.p(f'// skip "{op_name}", d    1575                 cw.p(f'// skip "{op_name}", duplicate reply value')
1558                 continue                         1576                 continue
1559                                                  1577 
1560             if op.req_value == op.rsp_value:     1578             if op.req_value == op.rsp_value:
1561                 cw.p(f'[{op.enum_name}] = "{o    1579                 cw.p(f'[{op.enum_name}] = "{op_name}",')
1562             else:                                1580             else:
1563                 cw.p(f'[{op.rsp_value}] = "{o    1581                 cw.p(f'[{op.rsp_value}] = "{op_name}",')
1564     cw.block_end(line=';')                       1582     cw.block_end(line=';')
1565     cw.nl()                                      1583     cw.nl()
1566                                                  1584 
1567     _put_enum_to_str_helper(cw, family.c_name    1585     _put_enum_to_str_helper(cw, family.c_name + '_op', map_name, 'op')
1568                                                  1586 
1569                                                  1587 
1570 def put_enum_to_str_fwd(family, cw, enum):       1588 def put_enum_to_str_fwd(family, cw, enum):
1571     args = [enum.user_type + ' value']           1589     args = [enum.user_type + ' value']
1572     cw.write_func_prot('const char *', f'{enu    1590     cw.write_func_prot('const char *', f'{enum.render_name}_str', args, suffix=';')
1573                                                  1591 
1574                                                  1592 
1575 def put_enum_to_str(family, cw, enum):           1593 def put_enum_to_str(family, cw, enum):
1576     map_name = f'{enum.render_name}_strmap'      1594     map_name = f'{enum.render_name}_strmap'
1577     cw.block_start(line=f"static const char *    1595     cw.block_start(line=f"static const char * const {map_name}[] =")
1578     for entry in enum.entries.values():          1596     for entry in enum.entries.values():
1579         cw.p(f'[{entry.value}] = "{entry.name    1597         cw.p(f'[{entry.value}] = "{entry.name}",')
1580     cw.block_end(line=';')                       1598     cw.block_end(line=';')
1581     cw.nl()                                      1599     cw.nl()
1582                                                  1600 
1583     _put_enum_to_str_helper(cw, enum.render_n    1601     _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum)
1584                                                  1602 
1585                                                  1603 
1586 def put_req_nested_prototype(ri, struct, suff    1604 def put_req_nested_prototype(ri, struct, suffix=';'):
1587     func_args = ['struct nlmsghdr *nlh',         1605     func_args = ['struct nlmsghdr *nlh',
1588                  'unsigned int attr_type',       1606                  'unsigned int attr_type',
1589                  f'{struct.ptr_name}obj']        1607                  f'{struct.ptr_name}obj']
1590                                                  1608 
1591     ri.cw.write_func_prot('int', f'{struct.re    1609     ri.cw.write_func_prot('int', f'{struct.render_name}_put', func_args,
1592                           suffix=suffix)         1610                           suffix=suffix)
1593                                                  1611 
1594                                                  1612 
1595 def put_req_nested(ri, struct):                  1613 def put_req_nested(ri, struct):
1596     put_req_nested_prototype(ri, struct, suff    1614     put_req_nested_prototype(ri, struct, suffix='')
1597     ri.cw.block_start()                          1615     ri.cw.block_start()
1598     ri.cw.write_func_lvar('struct nlattr *nes    1616     ri.cw.write_func_lvar('struct nlattr *nest;')
1599                                                  1617 
1600     ri.cw.p("nest = ynl_attr_nest_start(nlh,  !! 1618     ri.cw.p("nest = mnl_attr_nest_start(nlh, attr_type);")
1601                                                  1619 
1602     for _, arg in struct.member_list():          1620     for _, arg in struct.member_list():
1603         arg.attr_put(ri, "obj")                  1621         arg.attr_put(ri, "obj")
1604                                                  1622 
1605     ri.cw.p("ynl_attr_nest_end(nlh, nest);")  !! 1623     ri.cw.p("mnl_attr_nest_end(nlh, nest);")
1606                                                  1624 
1607     ri.cw.nl()                                   1625     ri.cw.nl()
1608     ri.cw.p('return 0;')                         1626     ri.cw.p('return 0;')
1609     ri.cw.block_end()                            1627     ri.cw.block_end()
1610     ri.cw.nl()                                   1628     ri.cw.nl()
1611                                                  1629 
1612                                                  1630 
1613 def _multi_parse(ri, struct, init_lines, loca    1631 def _multi_parse(ri, struct, init_lines, local_vars):
1614     if struct.nested:                            1632     if struct.nested:
1615         iter_line = "ynl_attr_for_each_nested !! 1633         iter_line = "mnl_attr_for_each_nested(attr, nested)"
1616     else:                                        1634     else:
1617         if ri.fixed_hdr:                         1635         if ri.fixed_hdr:
1618             local_vars += ['void *hdr;']         1636             local_vars += ['void *hdr;']
1619         iter_line = "ynl_attr_for_each(attr,  !! 1637         iter_line = "mnl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len)"
1620                                                  1638 
1621     array_nests = set()                          1639     array_nests = set()
1622     multi_attrs = set()                          1640     multi_attrs = set()
1623     needs_parg = False                           1641     needs_parg = False
1624     for arg, aspec in struct.member_list():      1642     for arg, aspec in struct.member_list():
1625         if aspec['type'] == 'indexed-array' a !! 1643         if aspec['type'] == 'array-nest':
1626             if aspec["sub-type"] == 'nest':   !! 1644             local_vars.append(f'const struct nlattr *attr_{aspec.c_name};')
1627                 local_vars.append(f'const str !! 1645             array_nests.add(arg)
1628                 array_nests.add(arg)          << 
1629             else:                             << 
1630                 raise Exception(f'Not support << 
1631         if 'multi-attr' in aspec:                1646         if 'multi-attr' in aspec:
1632             multi_attrs.add(arg)                 1647             multi_attrs.add(arg)
1633         needs_parg |= 'nested-attributes' in     1648         needs_parg |= 'nested-attributes' in aspec
1634     if array_nests or multi_attrs:               1649     if array_nests or multi_attrs:
1635         local_vars.append('int i;')              1650         local_vars.append('int i;')
1636     if needs_parg:                               1651     if needs_parg:
1637         local_vars.append('struct ynl_parse_a    1652         local_vars.append('struct ynl_parse_arg parg;')
1638         init_lines.append('parg.ys = yarg->ys    1653         init_lines.append('parg.ys = yarg->ys;')
1639                                                  1654 
1640     all_multi = array_nests | multi_attrs        1655     all_multi = array_nests | multi_attrs
1641                                                  1656 
1642     for anest in sorted(all_multi):              1657     for anest in sorted(all_multi):
1643         local_vars.append(f"unsigned int n_{s    1658         local_vars.append(f"unsigned int n_{struct[anest].c_name} = 0;")
1644                                                  1659 
1645     ri.cw.block_start()                          1660     ri.cw.block_start()
1646     ri.cw.write_func_lvar(local_vars)            1661     ri.cw.write_func_lvar(local_vars)
1647                                                  1662 
1648     for line in init_lines:                      1663     for line in init_lines:
1649         ri.cw.p(line)                            1664         ri.cw.p(line)
1650     ri.cw.nl()                                   1665     ri.cw.nl()
1651                                                  1666 
1652     for arg in struct.inherited:                 1667     for arg in struct.inherited:
1653         ri.cw.p(f'dst->{arg} = {arg};')          1668         ri.cw.p(f'dst->{arg} = {arg};')
1654                                                  1669 
1655     if ri.fixed_hdr:                             1670     if ri.fixed_hdr:
1656         ri.cw.p('hdr = ynl_nlmsg_data_offset( !! 1671         ri.cw.p('hdr = mnl_nlmsg_get_payload_offset(nlh, sizeof(struct genlmsghdr));')
1657         ri.cw.p(f"memcpy(&dst->_hdr, hdr, siz    1672         ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({ri.fixed_hdr}));")
1658     for anest in sorted(all_multi):              1673     for anest in sorted(all_multi):
1659         aspec = struct[anest]                    1674         aspec = struct[anest]
1660         ri.cw.p(f"if (dst->{aspec.c_name})")     1675         ri.cw.p(f"if (dst->{aspec.c_name})")
1661         ri.cw.p(f'return ynl_error_parse(yarg    1676         ri.cw.p(f'return ynl_error_parse(yarg, "attribute already present ({struct.attr_set.name}.{aspec.name})");')
1662                                                  1677 
1663     ri.cw.nl()                                   1678     ri.cw.nl()
1664     ri.cw.block_start(line=iter_line)            1679     ri.cw.block_start(line=iter_line)
1665     ri.cw.p('unsigned int type = ynl_attr_typ !! 1680     ri.cw.p('unsigned int type = mnl_attr_get_type(attr);')
1666     ri.cw.nl()                                   1681     ri.cw.nl()
1667                                                  1682 
1668     first = True                                 1683     first = True
1669     for _, arg in struct.member_list():          1684     for _, arg in struct.member_list():
1670         good = arg.attr_get(ri, 'dst', first=    1685         good = arg.attr_get(ri, 'dst', first=first)
1671         # First may be 'unused' or 'pad', ign    1686         # First may be 'unused' or 'pad', ignore those
1672         first &= not good                        1687         first &= not good
1673                                                  1688 
1674     ri.cw.block_end()                            1689     ri.cw.block_end()
1675     ri.cw.nl()                                   1690     ri.cw.nl()
1676                                                  1691 
1677     for anest in sorted(array_nests):            1692     for anest in sorted(array_nests):
1678         aspec = struct[anest]                    1693         aspec = struct[anest]
1679                                                  1694 
1680         ri.cw.block_start(line=f"if (n_{aspec    1695         ri.cw.block_start(line=f"if (n_{aspec.c_name})")
1681         ri.cw.p(f"dst->{aspec.c_name} = callo !! 1696         ri.cw.p(f"dst->{aspec.c_name} = calloc({aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
1682         ri.cw.p(f"dst->n_{aspec.c_name} = n_{    1697         ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};")
1683         ri.cw.p('i = 0;')                        1698         ri.cw.p('i = 0;')
1684         ri.cw.p(f"parg.rsp_policy = &{aspec.n    1699         ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
1685         ri.cw.block_start(line=f"ynl_attr_for !! 1700         ri.cw.block_start(line=f"mnl_attr_for_each_nested(attr, attr_{aspec.c_name})")
1686         ri.cw.p(f"parg.data = &dst->{aspec.c_    1701         ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];")
1687         ri.cw.p(f"if ({aspec.nested_render_na !! 1702         ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr, mnl_attr_get_type(attr)))")
1688         ri.cw.p('return YNL_PARSE_CB_ERROR;') !! 1703         ri.cw.p('return MNL_CB_ERROR;')
1689         ri.cw.p('i++;')                          1704         ri.cw.p('i++;')
1690         ri.cw.block_end()                        1705         ri.cw.block_end()
1691         ri.cw.block_end()                        1706         ri.cw.block_end()
1692     ri.cw.nl()                                   1707     ri.cw.nl()
1693                                                  1708 
1694     for anest in sorted(multi_attrs):            1709     for anest in sorted(multi_attrs):
1695         aspec = struct[anest]                    1710         aspec = struct[anest]
1696         ri.cw.block_start(line=f"if (n_{aspec    1711         ri.cw.block_start(line=f"if (n_{aspec.c_name})")
1697         ri.cw.p(f"dst->{aspec.c_name} = callo    1712         ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
1698         ri.cw.p(f"dst->n_{aspec.c_name} = n_{    1713         ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};")
1699         ri.cw.p('i = 0;')                        1714         ri.cw.p('i = 0;')
1700         if 'nested-attributes' in aspec:         1715         if 'nested-attributes' in aspec:
1701             ri.cw.p(f"parg.rsp_policy = &{asp    1716             ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
1702         ri.cw.block_start(line=iter_line)        1717         ri.cw.block_start(line=iter_line)
1703         ri.cw.block_start(line=f"if (ynl_attr !! 1718         ri.cw.block_start(line=f"if (mnl_attr_get_type(attr) == {aspec.enum_name})")
1704         if 'nested-attributes' in aspec:         1719         if 'nested-attributes' in aspec:
1705             ri.cw.p(f"parg.data = &dst->{aspe    1720             ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];")
1706             ri.cw.p(f"if ({aspec.nested_rende    1721             ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr))")
1707             ri.cw.p('return YNL_PARSE_CB_ERRO !! 1722             ri.cw.p('return MNL_CB_ERROR;')
1708         elif aspec.type in scalars:              1723         elif aspec.type in scalars:
1709             ri.cw.p(f"dst->{aspec.c_name}[i]  !! 1724             ri.cw.p(f"dst->{aspec.c_name}[i] = mnl_attr_get_{aspec.mnl_type()}(attr);")
1710         else:                                    1725         else:
1711             raise Exception('Nest parsing typ    1726             raise Exception('Nest parsing type not supported yet')
1712         ri.cw.p('i++;')                          1727         ri.cw.p('i++;')
1713         ri.cw.block_end()                        1728         ri.cw.block_end()
1714         ri.cw.block_end()                        1729         ri.cw.block_end()
1715         ri.cw.block_end()                        1730         ri.cw.block_end()
1716     ri.cw.nl()                                   1731     ri.cw.nl()
1717                                                  1732 
1718     if struct.nested:                            1733     if struct.nested:
1719         ri.cw.p('return 0;')                     1734         ri.cw.p('return 0;')
1720     else:                                        1735     else:
1721         ri.cw.p('return YNL_PARSE_CB_OK;')    !! 1736         ri.cw.p('return MNL_CB_OK;')
1722     ri.cw.block_end()                            1737     ri.cw.block_end()
1723     ri.cw.nl()                                   1738     ri.cw.nl()
1724                                                  1739 
1725                                                  1740 
1726 def parse_rsp_nested_prototype(ri, struct, su    1741 def parse_rsp_nested_prototype(ri, struct, suffix=';'):
1727     func_args = ['struct ynl_parse_arg *yarg'    1742     func_args = ['struct ynl_parse_arg *yarg',
1728                  'const struct nlattr *nested    1743                  'const struct nlattr *nested']
1729     for arg in struct.inherited:                 1744     for arg in struct.inherited:
1730         func_args.append('__u32 ' + arg)         1745         func_args.append('__u32 ' + arg)
1731                                                  1746 
1732     ri.cw.write_func_prot('int', f'{struct.re    1747     ri.cw.write_func_prot('int', f'{struct.render_name}_parse', func_args,
1733                           suffix=suffix)         1748                           suffix=suffix)
1734                                                  1749 
1735                                                  1750 
1736 def parse_rsp_nested(ri, struct):                1751 def parse_rsp_nested(ri, struct):
1737     parse_rsp_nested_prototype(ri, struct, su    1752     parse_rsp_nested_prototype(ri, struct, suffix='')
1738                                                  1753 
1739     local_vars = ['const struct nlattr *attr;    1754     local_vars = ['const struct nlattr *attr;',
1740                   f'{struct.ptr_name}dst = ya    1755                   f'{struct.ptr_name}dst = yarg->data;']
1741     init_lines = []                              1756     init_lines = []
1742                                                  1757 
1743     _multi_parse(ri, struct, init_lines, loca    1758     _multi_parse(ri, struct, init_lines, local_vars)
1744                                                  1759 
1745                                                  1760 
1746 def parse_rsp_msg(ri, deref=False):              1761 def parse_rsp_msg(ri, deref=False):
1747     if 'reply' not in ri.op[ri.op_mode] and r    1762     if 'reply' not in ri.op[ri.op_mode] and ri.op_mode != 'event':
1748         return                                   1763         return
1749                                                  1764 
1750     func_args = ['const struct nlmsghdr *nlh'    1765     func_args = ['const struct nlmsghdr *nlh',
1751                  'struct ynl_parse_arg *yarg' !! 1766                  'void *data']
1752                                                  1767 
1753     local_vars = [f'{type_name(ri, "reply", d    1768     local_vars = [f'{type_name(ri, "reply", deref=deref)} *dst;',
                                                   >> 1769                   'struct ynl_parse_arg *yarg = data;',
1754                   'const struct nlattr *attr;    1770                   'const struct nlattr *attr;']
1755     init_lines = ['dst = yarg->data;']           1771     init_lines = ['dst = yarg->data;']
1756                                                  1772 
1757     ri.cw.write_func_prot('int', f'{op_prefix    1773     ri.cw.write_func_prot('int', f'{op_prefix(ri, "reply", deref=deref)}_parse', func_args)
1758                                                  1774 
1759     if ri.struct["reply"].member_list():         1775     if ri.struct["reply"].member_list():
1760         _multi_parse(ri, ri.struct["reply"],     1776         _multi_parse(ri, ri.struct["reply"], init_lines, local_vars)
1761     else:                                        1777     else:
1762         # Empty reply                            1778         # Empty reply
1763         ri.cw.block_start()                      1779         ri.cw.block_start()
1764         ri.cw.p('return YNL_PARSE_CB_OK;')    !! 1780         ri.cw.p('return MNL_CB_OK;')
1765         ri.cw.block_end()                        1781         ri.cw.block_end()
1766         ri.cw.nl()                               1782         ri.cw.nl()
1767                                                  1783 
1768                                                  1784 
1769 def print_req(ri):                               1785 def print_req(ri):
1770     ret_ok = '0'                                 1786     ret_ok = '0'
1771     ret_err = '-1'                               1787     ret_err = '-1'
1772     direction = "request"                        1788     direction = "request"
1773     local_vars = ['struct ynl_req_state yrs =    1789     local_vars = ['struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };',
1774                   'struct nlmsghdr *nlh;',       1790                   'struct nlmsghdr *nlh;',
1775                   'int err;']                    1791                   'int err;']
1776                                                  1792 
1777     if 'reply' in ri.op[ri.op_mode]:             1793     if 'reply' in ri.op[ri.op_mode]:
1778         ret_ok = 'rsp'                           1794         ret_ok = 'rsp'
1779         ret_err = 'NULL'                         1795         ret_err = 'NULL'
1780         local_vars += [f'{type_name(ri, rdir(    1796         local_vars += [f'{type_name(ri, rdir(direction))} *rsp;']
1781                                                  1797 
1782     if ri.fixed_hdr:                             1798     if ri.fixed_hdr:
1783         local_vars += ['size_t hdr_len;',        1799         local_vars += ['size_t hdr_len;',
1784                        'void *hdr;']             1800                        'void *hdr;']
1785                                                  1801 
1786     print_prototype(ri, direction, terminate=    1802     print_prototype(ri, direction, terminate=False)
1787     ri.cw.block_start()                          1803     ri.cw.block_start()
1788     ri.cw.write_func_lvar(local_vars)            1804     ri.cw.write_func_lvar(local_vars)
1789                                                  1805 
1790     ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {    1806     ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
1791                                                  1807 
1792     ri.cw.p(f"ys->req_policy = &{ri.struct['r    1808     ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;")
1793     if 'reply' in ri.op[ri.op_mode]:             1809     if 'reply' in ri.op[ri.op_mode]:
1794         ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.    1810         ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
1795     ri.cw.nl()                                   1811     ri.cw.nl()
1796                                                  1812 
1797     if ri.fixed_hdr:                             1813     if ri.fixed_hdr:
1798         ri.cw.p("hdr_len = sizeof(req->_hdr);    1814         ri.cw.p("hdr_len = sizeof(req->_hdr);")
1799         ri.cw.p("hdr = ynl_nlmsg_put_extra_he !! 1815         ri.cw.p("hdr = mnl_nlmsg_put_extra_header(nlh, hdr_len);")
1800         ri.cw.p("memcpy(hdr, &req->_hdr, hdr_    1816         ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);")
1801         ri.cw.nl()                               1817         ri.cw.nl()
1802                                                  1818 
1803     for _, attr in ri.struct["request"].membe    1819     for _, attr in ri.struct["request"].member_list():
1804         attr.attr_put(ri, "req")                 1820         attr.attr_put(ri, "req")
1805     ri.cw.nl()                                   1821     ri.cw.nl()
1806                                                  1822 
1807     if 'reply' in ri.op[ri.op_mode]:             1823     if 'reply' in ri.op[ri.op_mode]:
1808         ri.cw.p('rsp = calloc(1, sizeof(*rsp)    1824         ri.cw.p('rsp = calloc(1, sizeof(*rsp));')
1809         ri.cw.p('yrs.yarg.data = rsp;')          1825         ri.cw.p('yrs.yarg.data = rsp;')
1810         ri.cw.p(f"yrs.cb = {op_prefix(ri, 're    1826         ri.cw.p(f"yrs.cb = {op_prefix(ri, 'reply')}_parse;")
1811         if ri.op.value is not None:              1827         if ri.op.value is not None:
1812             ri.cw.p(f'yrs.rsp_cmd = {ri.op.en    1828             ri.cw.p(f'yrs.rsp_cmd = {ri.op.enum_name};')
1813         else:                                    1829         else:
1814             ri.cw.p(f'yrs.rsp_cmd = {ri.op.rs    1830             ri.cw.p(f'yrs.rsp_cmd = {ri.op.rsp_value};')
1815         ri.cw.nl()                               1831         ri.cw.nl()
1816     ri.cw.p("err = ynl_exec(ys, nlh, &yrs);")    1832     ri.cw.p("err = ynl_exec(ys, nlh, &yrs);")
1817     ri.cw.p('if (err < 0)')                      1833     ri.cw.p('if (err < 0)')
1818     if 'reply' in ri.op[ri.op_mode]:             1834     if 'reply' in ri.op[ri.op_mode]:
1819         ri.cw.p('goto err_free;')                1835         ri.cw.p('goto err_free;')
1820     else:                                        1836     else:
1821         ri.cw.p('return -1;')                    1837         ri.cw.p('return -1;')
1822     ri.cw.nl()                                   1838     ri.cw.nl()
1823                                                  1839 
1824     ri.cw.p(f"return {ret_ok};")                 1840     ri.cw.p(f"return {ret_ok};")
1825     ri.cw.nl()                                   1841     ri.cw.nl()
1826                                                  1842 
1827     if 'reply' in ri.op[ri.op_mode]:             1843     if 'reply' in ri.op[ri.op_mode]:
1828         ri.cw.p('err_free:')                     1844         ri.cw.p('err_free:')
1829         ri.cw.p(f"{call_free(ri, rdir(directi    1845         ri.cw.p(f"{call_free(ri, rdir(direction), 'rsp')}")
1830         ri.cw.p(f"return {ret_err};")            1846         ri.cw.p(f"return {ret_err};")
1831                                                  1847 
1832     ri.cw.block_end()                            1848     ri.cw.block_end()
1833                                                  1849 
1834                                                  1850 
1835 def print_dump(ri):                              1851 def print_dump(ri):
1836     direction = "request"                        1852     direction = "request"
1837     print_prototype(ri, direction, terminate=    1853     print_prototype(ri, direction, terminate=False)
1838     ri.cw.block_start()                          1854     ri.cw.block_start()
1839     local_vars = ['struct ynl_dump_state yds     1855     local_vars = ['struct ynl_dump_state yds = {};',
1840                   'struct nlmsghdr *nlh;',       1856                   'struct nlmsghdr *nlh;',
1841                   'int err;']                    1857                   'int err;']
1842                                                  1858 
1843     if ri.fixed_hdr:                             1859     if ri.fixed_hdr:
1844         local_vars += ['size_t hdr_len;',        1860         local_vars += ['size_t hdr_len;',
1845                        'void *hdr;']             1861                        'void *hdr;']
1846                                                  1862 
1847     ri.cw.write_func_lvar(local_vars)            1863     ri.cw.write_func_lvar(local_vars)
1848                                                  1864 
1849     ri.cw.p('yds.yarg.ys = ys;')              !! 1865     ri.cw.p('yds.ys = ys;')
1850     ri.cw.p(f"yds.yarg.rsp_policy = &{ri.stru << 
1851     ri.cw.p("yds.yarg.data = NULL;")          << 
1852     ri.cw.p(f"yds.alloc_sz = sizeof({type_nam    1866     ri.cw.p(f"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});")
1853     ri.cw.p(f"yds.cb = {op_prefix(ri, 'reply'    1867     ri.cw.p(f"yds.cb = {op_prefix(ri, 'reply', deref=True)}_parse;")
1854     if ri.op.value is not None:                  1868     if ri.op.value is not None:
1855         ri.cw.p(f'yds.rsp_cmd = {ri.op.enum_n    1869         ri.cw.p(f'yds.rsp_cmd = {ri.op.enum_name};')
1856     else:                                        1870     else:
1857         ri.cw.p(f'yds.rsp_cmd = {ri.op.rsp_va    1871         ri.cw.p(f'yds.rsp_cmd = {ri.op.rsp_value};')
                                                   >> 1872     ri.cw.p(f"yds.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
1858     ri.cw.nl()                                   1873     ri.cw.nl()
1859     ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys,     1874     ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
1860                                                  1875 
1861     if ri.fixed_hdr:                             1876     if ri.fixed_hdr:
1862         ri.cw.p("hdr_len = sizeof(req->_hdr);    1877         ri.cw.p("hdr_len = sizeof(req->_hdr);")
1863         ri.cw.p("hdr = ynl_nlmsg_put_extra_he !! 1878         ri.cw.p("hdr = mnl_nlmsg_put_extra_header(nlh, hdr_len);")
1864         ri.cw.p("memcpy(hdr, &req->_hdr, hdr_    1879         ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);")
1865         ri.cw.nl()                               1880         ri.cw.nl()
1866                                                  1881 
1867     if "request" in ri.op[ri.op_mode]:           1882     if "request" in ri.op[ri.op_mode]:
1868         ri.cw.p(f"ys->req_policy = &{ri.struc    1883         ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;")
1869         ri.cw.nl()                               1884         ri.cw.nl()
1870         for _, attr in ri.struct["request"].m    1885         for _, attr in ri.struct["request"].member_list():
1871             attr.attr_put(ri, "req")             1886             attr.attr_put(ri, "req")
1872     ri.cw.nl()                                   1887     ri.cw.nl()
1873                                                  1888 
1874     ri.cw.p('err = ynl_exec_dump(ys, nlh, &yd    1889     ri.cw.p('err = ynl_exec_dump(ys, nlh, &yds);')
1875     ri.cw.p('if (err < 0)')                      1890     ri.cw.p('if (err < 0)')
1876     ri.cw.p('goto free_list;')                   1891     ri.cw.p('goto free_list;')
1877     ri.cw.nl()                                   1892     ri.cw.nl()
1878                                                  1893 
1879     ri.cw.p('return yds.first;')                 1894     ri.cw.p('return yds.first;')
1880     ri.cw.nl()                                   1895     ri.cw.nl()
1881     ri.cw.p('free_list:')                        1896     ri.cw.p('free_list:')
1882     ri.cw.p(call_free(ri, rdir(direction), 'y    1897     ri.cw.p(call_free(ri, rdir(direction), 'yds.first'))
1883     ri.cw.p('return NULL;')                      1898     ri.cw.p('return NULL;')
1884     ri.cw.block_end()                            1899     ri.cw.block_end()
1885                                                  1900 
1886                                                  1901 
1887 def call_free(ri, direction, var):               1902 def call_free(ri, direction, var):
1888     return f"{op_prefix(ri, direction)}_free(    1903     return f"{op_prefix(ri, direction)}_free({var});"
1889                                                  1904 
1890                                                  1905 
1891 def free_arg_name(direction):                    1906 def free_arg_name(direction):
1892     if direction:                                1907     if direction:
1893         return direction_to_suffix[direction]    1908         return direction_to_suffix[direction][1:]
1894     return 'obj'                                 1909     return 'obj'
1895                                                  1910 
1896                                                  1911 
1897 def print_alloc_wrapper(ri, direction):          1912 def print_alloc_wrapper(ri, direction):
1898     name = op_prefix(ri, direction)              1913     name = op_prefix(ri, direction)
1899     ri.cw.write_func_prot(f'static inline str    1914     ri.cw.write_func_prot(f'static inline struct {name} *', f"{name}_alloc", [f"void"])
1900     ri.cw.block_start()                          1915     ri.cw.block_start()
1901     ri.cw.p(f'return calloc(1, sizeof(struct     1916     ri.cw.p(f'return calloc(1, sizeof(struct {name}));')
1902     ri.cw.block_end()                            1917     ri.cw.block_end()
1903                                                  1918 
1904                                                  1919 
1905 def print_free_prototype(ri, direction, suffi    1920 def print_free_prototype(ri, direction, suffix=';'):
1906     name = op_prefix(ri, direction)              1921     name = op_prefix(ri, direction)
1907     struct_name = name                           1922     struct_name = name
1908     if ri.type_name_conflict:                    1923     if ri.type_name_conflict:
1909         struct_name += '_'                       1924         struct_name += '_'
1910     arg = free_arg_name(direction)               1925     arg = free_arg_name(direction)
1911     ri.cw.write_func_prot('void', f"{name}_fr    1926     ri.cw.write_func_prot('void', f"{name}_free", [f"struct {struct_name} *{arg}"], suffix=suffix)
1912                                                  1927 
1913                                                  1928 
1914 def _print_type(ri, direction, struct):          1929 def _print_type(ri, direction, struct):
1915     suffix = f'_{ri.type_name}{direction_to_s    1930     suffix = f'_{ri.type_name}{direction_to_suffix[direction]}'
1916     if not direction and ri.type_name_conflic    1931     if not direction and ri.type_name_conflict:
1917         suffix += '_'                            1932         suffix += '_'
1918                                                  1933 
1919     if ri.op_mode == 'dump':                     1934     if ri.op_mode == 'dump':
1920         suffix += '_dump'                        1935         suffix += '_dump'
1921                                                  1936 
1922     ri.cw.block_start(line=f"struct {ri.famil    1937     ri.cw.block_start(line=f"struct {ri.family.c_name}{suffix}")
1923                                                  1938 
1924     if ri.fixed_hdr:                             1939     if ri.fixed_hdr:
1925         ri.cw.p(ri.fixed_hdr + ' _hdr;')         1940         ri.cw.p(ri.fixed_hdr + ' _hdr;')
1926         ri.cw.nl()                               1941         ri.cw.nl()
1927                                                  1942 
1928     meta_started = False                         1943     meta_started = False
1929     for _, attr in struct.member_list():         1944     for _, attr in struct.member_list():
1930         for type_filter in ['len', 'bit']:       1945         for type_filter in ['len', 'bit']:
1931             line = attr.presence_member(ri.ku    1946             line = attr.presence_member(ri.ku_space, type_filter)
1932             if line:                             1947             if line:
1933                 if not meta_started:             1948                 if not meta_started:
1934                     ri.cw.block_start(line=f"    1949                     ri.cw.block_start(line=f"struct")
1935                     meta_started = True          1950                     meta_started = True
1936                 ri.cw.p(line)                    1951                 ri.cw.p(line)
1937     if meta_started:                             1952     if meta_started:
1938         ri.cw.block_end(line='_present;')        1953         ri.cw.block_end(line='_present;')
1939         ri.cw.nl()                               1954         ri.cw.nl()
1940                                                  1955 
1941     for arg in struct.inherited:                 1956     for arg in struct.inherited:
1942         ri.cw.p(f"__u32 {arg};")                 1957         ri.cw.p(f"__u32 {arg};")
1943                                                  1958 
1944     for _, attr in struct.member_list():         1959     for _, attr in struct.member_list():
1945         attr.struct_member(ri)                   1960         attr.struct_member(ri)
1946                                                  1961 
1947     ri.cw.block_end(line=';')                    1962     ri.cw.block_end(line=';')
1948     ri.cw.nl()                                   1963     ri.cw.nl()
1949                                                  1964 
1950                                                  1965 
1951 def print_type(ri, direction):                   1966 def print_type(ri, direction):
1952     _print_type(ri, direction, ri.struct[dire    1967     _print_type(ri, direction, ri.struct[direction])
1953                                                  1968 
1954                                                  1969 
1955 def print_type_full(ri, struct):                 1970 def print_type_full(ri, struct):
1956     _print_type(ri, "", struct)                  1971     _print_type(ri, "", struct)
1957                                                  1972 
1958                                                  1973 
1959 def print_type_helpers(ri, direction, deref=F    1974 def print_type_helpers(ri, direction, deref=False):
1960     print_free_prototype(ri, direction)          1975     print_free_prototype(ri, direction)
1961     ri.cw.nl()                                   1976     ri.cw.nl()
1962                                                  1977 
1963     if ri.ku_space == 'user' and direction ==    1978     if ri.ku_space == 'user' and direction == 'request':
1964         for _, attr in ri.struct[direction].m    1979         for _, attr in ri.struct[direction].member_list():
1965             attr.setter(ri, ri.attr_set, dire    1980             attr.setter(ri, ri.attr_set, direction, deref=deref)
1966     ri.cw.nl()                                   1981     ri.cw.nl()
1967                                                  1982 
1968                                                  1983 
1969 def print_req_type_helpers(ri):                  1984 def print_req_type_helpers(ri):
1970     if len(ri.struct["request"].attr_list) ==    1985     if len(ri.struct["request"].attr_list) == 0:
1971         return                                   1986         return
1972     print_alloc_wrapper(ri, "request")           1987     print_alloc_wrapper(ri, "request")
1973     print_type_helpers(ri, "request")            1988     print_type_helpers(ri, "request")
1974                                                  1989 
1975                                                  1990 
1976 def print_rsp_type_helpers(ri):                  1991 def print_rsp_type_helpers(ri):
1977     if 'reply' not in ri.op[ri.op_mode]:         1992     if 'reply' not in ri.op[ri.op_mode]:
1978         return                                   1993         return
1979     print_type_helpers(ri, "reply")              1994     print_type_helpers(ri, "reply")
1980                                                  1995 
1981                                                  1996 
1982 def print_parse_prototype(ri, direction, term    1997 def print_parse_prototype(ri, direction, terminate=True):
1983     suffix = "_rsp" if direction == "reply" e    1998     suffix = "_rsp" if direction == "reply" else "_req"
1984     term = ';' if terminate else ''              1999     term = ';' if terminate else ''
1985                                                  2000 
1986     ri.cw.write_func_prot('void', f"{ri.op.re    2001     ri.cw.write_func_prot('void', f"{ri.op.render_name}{suffix}_parse",
1987                           ['const struct nlat    2002                           ['const struct nlattr **tb',
1988                            f"struct {ri.op.re    2003                            f"struct {ri.op.render_name}{suffix} *req"],
1989                           suffix=term)           2004                           suffix=term)
1990                                                  2005 
1991                                                  2006 
1992 def print_req_type(ri):                          2007 def print_req_type(ri):
1993     if len(ri.struct["request"].attr_list) ==    2008     if len(ri.struct["request"].attr_list) == 0:
1994         return                                   2009         return
1995     print_type(ri, "request")                    2010     print_type(ri, "request")
1996                                                  2011 
1997                                                  2012 
1998 def print_req_free(ri):                          2013 def print_req_free(ri):
1999     if 'request' not in ri.op[ri.op_mode]:       2014     if 'request' not in ri.op[ri.op_mode]:
2000         return                                   2015         return
2001     _free_type(ri, 'request', ri.struct['requ    2016     _free_type(ri, 'request', ri.struct['request'])
2002                                                  2017 
2003                                                  2018 
2004 def print_rsp_type(ri):                          2019 def print_rsp_type(ri):
2005     if (ri.op_mode == 'do' or ri.op_mode == '    2020     if (ri.op_mode == 'do' or ri.op_mode == 'dump') and 'reply' in ri.op[ri.op_mode]:
2006         direction = 'reply'                      2021         direction = 'reply'
2007     elif ri.op_mode == 'event':                  2022     elif ri.op_mode == 'event':
2008         direction = 'reply'                      2023         direction = 'reply'
2009     else:                                        2024     else:
2010         return                                   2025         return
2011     print_type(ri, direction)                    2026     print_type(ri, direction)
2012                                                  2027 
2013                                                  2028 
2014 def print_wrapped_type(ri):                      2029 def print_wrapped_type(ri):
2015     ri.cw.block_start(line=f"{type_name(ri, '    2030     ri.cw.block_start(line=f"{type_name(ri, 'reply')}")
2016     if ri.op_mode == 'dump':                     2031     if ri.op_mode == 'dump':
2017         ri.cw.p(f"{type_name(ri, 'reply')} *n    2032         ri.cw.p(f"{type_name(ri, 'reply')} *next;")
2018     elif ri.op_mode == 'notify' or ri.op_mode    2033     elif ri.op_mode == 'notify' or ri.op_mode == 'event':
2019         ri.cw.p('__u16 family;')                 2034         ri.cw.p('__u16 family;')
2020         ri.cw.p('__u8 cmd;')                     2035         ri.cw.p('__u8 cmd;')
2021         ri.cw.p('struct ynl_ntf_base_type *ne    2036         ri.cw.p('struct ynl_ntf_base_type *next;')
2022         ri.cw.p(f"void (*free)({type_name(ri,    2037         ri.cw.p(f"void (*free)({type_name(ri, 'reply')} *ntf);")
2023     ri.cw.p(f"{type_name(ri, 'reply', deref=T    2038     ri.cw.p(f"{type_name(ri, 'reply', deref=True)} obj __attribute__((aligned(8)));")
2024     ri.cw.block_end(line=';')                    2039     ri.cw.block_end(line=';')
2025     ri.cw.nl()                                   2040     ri.cw.nl()
2026     print_free_prototype(ri, 'reply')            2041     print_free_prototype(ri, 'reply')
2027     ri.cw.nl()                                   2042     ri.cw.nl()
2028                                                  2043 
2029                                                  2044 
2030 def _free_type_members_iter(ri, struct):         2045 def _free_type_members_iter(ri, struct):
2031     for _, attr in struct.member_list():         2046     for _, attr in struct.member_list():
2032         if attr.free_needs_iter():               2047         if attr.free_needs_iter():
2033             ri.cw.p('unsigned int i;')           2048             ri.cw.p('unsigned int i;')
2034             ri.cw.nl()                           2049             ri.cw.nl()
2035             break                                2050             break
2036                                                  2051 
2037                                                  2052 
2038 def _free_type_members(ri, var, struct, ref='    2053 def _free_type_members(ri, var, struct, ref=''):
2039     for _, attr in struct.member_list():         2054     for _, attr in struct.member_list():
2040         attr.free(ri, var, ref)                  2055         attr.free(ri, var, ref)
2041                                                  2056 
2042                                                  2057 
2043 def _free_type(ri, direction, struct):           2058 def _free_type(ri, direction, struct):
2044     var = free_arg_name(direction)               2059     var = free_arg_name(direction)
2045                                                  2060 
2046     print_free_prototype(ri, direction, suffi    2061     print_free_prototype(ri, direction, suffix='')
2047     ri.cw.block_start()                          2062     ri.cw.block_start()
2048     _free_type_members_iter(ri, struct)          2063     _free_type_members_iter(ri, struct)
2049     _free_type_members(ri, var, struct)          2064     _free_type_members(ri, var, struct)
2050     if direction:                                2065     if direction:
2051         ri.cw.p(f'free({var});')                 2066         ri.cw.p(f'free({var});')
2052     ri.cw.block_end()                            2067     ri.cw.block_end()
2053     ri.cw.nl()                                   2068     ri.cw.nl()
2054                                                  2069 
2055                                                  2070 
2056 def free_rsp_nested_prototype(ri):               2071 def free_rsp_nested_prototype(ri):
2057         print_free_prototype(ri, "")             2072         print_free_prototype(ri, "")
2058                                                  2073 
2059                                                  2074 
2060 def free_rsp_nested(ri, struct):                 2075 def free_rsp_nested(ri, struct):
2061     _free_type(ri, "", struct)                   2076     _free_type(ri, "", struct)
2062                                                  2077 
2063                                                  2078 
2064 def print_rsp_free(ri):                          2079 def print_rsp_free(ri):
2065     if 'reply' not in ri.op[ri.op_mode]:         2080     if 'reply' not in ri.op[ri.op_mode]:
2066         return                                   2081         return
2067     _free_type(ri, 'reply', ri.struct['reply'    2082     _free_type(ri, 'reply', ri.struct['reply'])
2068                                                  2083 
2069                                                  2084 
2070 def print_dump_type_free(ri):                    2085 def print_dump_type_free(ri):
2071     sub_type = type_name(ri, 'reply')            2086     sub_type = type_name(ri, 'reply')
2072                                                  2087 
2073     print_free_prototype(ri, 'reply', suffix=    2088     print_free_prototype(ri, 'reply', suffix='')
2074     ri.cw.block_start()                          2089     ri.cw.block_start()
2075     ri.cw.p(f"{sub_type} *next = rsp;")          2090     ri.cw.p(f"{sub_type} *next = rsp;")
2076     ri.cw.nl()                                   2091     ri.cw.nl()
2077     ri.cw.block_start(line='while ((void *)ne    2092     ri.cw.block_start(line='while ((void *)next != YNL_LIST_END)')
2078     _free_type_members_iter(ri, ri.struct['re    2093     _free_type_members_iter(ri, ri.struct['reply'])
2079     ri.cw.p('rsp = next;')                       2094     ri.cw.p('rsp = next;')
2080     ri.cw.p('next = rsp->next;')                 2095     ri.cw.p('next = rsp->next;')
2081     ri.cw.nl()                                   2096     ri.cw.nl()
2082                                                  2097 
2083     _free_type_members(ri, 'rsp', ri.struct['    2098     _free_type_members(ri, 'rsp', ri.struct['reply'], ref='obj.')
2084     ri.cw.p(f'free(rsp);')                       2099     ri.cw.p(f'free(rsp);')
2085     ri.cw.block_end()                            2100     ri.cw.block_end()
2086     ri.cw.block_end()                            2101     ri.cw.block_end()
2087     ri.cw.nl()                                   2102     ri.cw.nl()
2088                                                  2103 
2089                                                  2104 
2090 def print_ntf_type_free(ri):                     2105 def print_ntf_type_free(ri):
2091     print_free_prototype(ri, 'reply', suffix=    2106     print_free_prototype(ri, 'reply', suffix='')
2092     ri.cw.block_start()                          2107     ri.cw.block_start()
2093     _free_type_members_iter(ri, ri.struct['re    2108     _free_type_members_iter(ri, ri.struct['reply'])
2094     _free_type_members(ri, 'rsp', ri.struct['    2109     _free_type_members(ri, 'rsp', ri.struct['reply'], ref='obj.')
2095     ri.cw.p(f'free(rsp);')                       2110     ri.cw.p(f'free(rsp);')
2096     ri.cw.block_end()                            2111     ri.cw.block_end()
2097     ri.cw.nl()                                   2112     ri.cw.nl()
2098                                                  2113 
2099                                                  2114 
2100 def print_req_policy_fwd(cw, struct, ri=None,    2115 def print_req_policy_fwd(cw, struct, ri=None, terminate=True):
2101     if terminate and ri and policy_should_be_    2116     if terminate and ri and policy_should_be_static(struct.family):
2102         return                                   2117         return
2103                                                  2118 
2104     if terminate:                                2119     if terminate:
2105         prefix = 'extern '                       2120         prefix = 'extern '
2106     else:                                        2121     else:
2107         if ri and policy_should_be_static(str    2122         if ri and policy_should_be_static(struct.family):
2108             prefix = 'static '                   2123             prefix = 'static '
2109         else:                                    2124         else:
2110             prefix = ''                          2125             prefix = ''
2111                                                  2126 
2112     suffix = ';' if terminate else ' = {'        2127     suffix = ';' if terminate else ' = {'
2113                                                  2128 
2114     max_attr = struct.attr_max_val               2129     max_attr = struct.attr_max_val
2115     if ri:                                       2130     if ri:
2116         name = ri.op.render_name                 2131         name = ri.op.render_name
2117         if ri.op.dual_policy:                    2132         if ri.op.dual_policy:
2118             name += '_' + ri.op_mode             2133             name += '_' + ri.op_mode
2119     else:                                        2134     else:
2120         name = struct.render_name                2135         name = struct.render_name
2121     cw.p(f"{prefix}const struct nla_policy {n    2136     cw.p(f"{prefix}const struct nla_policy {name}_nl_policy[{max_attr.enum_name} + 1]{suffix}")
2122                                                  2137 
2123                                                  2138 
2124 def print_req_policy(cw, struct, ri=None):       2139 def print_req_policy(cw, struct, ri=None):
2125     if ri and ri.op:                             2140     if ri and ri.op:
2126         cw.ifdef_block(ri.op.get('config-cond    2141         cw.ifdef_block(ri.op.get('config-cond', None))
2127     print_req_policy_fwd(cw, struct, ri=ri, t    2142     print_req_policy_fwd(cw, struct, ri=ri, terminate=False)
2128     for _, arg in struct.member_list():          2143     for _, arg in struct.member_list():
2129         arg.attr_policy(cw)                      2144         arg.attr_policy(cw)
2130     cw.p("};")                                   2145     cw.p("};")
2131     cw.ifdef_block(None)                         2146     cw.ifdef_block(None)
2132     cw.nl()                                      2147     cw.nl()
2133                                                  2148 
2134                                                  2149 
2135 def kernel_can_gen_family_struct(family):        2150 def kernel_can_gen_family_struct(family):
2136     return family.proto == 'genetlink'           2151     return family.proto == 'genetlink'
2137                                                  2152 
2138                                                  2153 
2139 def policy_should_be_static(family):             2154 def policy_should_be_static(family):
2140     return family.kernel_policy == 'split' or    2155     return family.kernel_policy == 'split' or kernel_can_gen_family_struct(family)
2141                                                  2156 
2142                                                  2157 
2143 def print_kernel_policy_ranges(family, cw):      2158 def print_kernel_policy_ranges(family, cw):
2144     first = True                                 2159     first = True
2145     for _, attr_set in family.attr_sets.items    2160     for _, attr_set in family.attr_sets.items():
2146         if attr_set.subset_of:                   2161         if attr_set.subset_of:
2147             continue                             2162             continue
2148                                                  2163 
2149         for _, attr in attr_set.items():         2164         for _, attr in attr_set.items():
2150             if not attr.request:                 2165             if not attr.request:
2151                 continue                         2166                 continue
2152             if 'full-range' not in attr.check    2167             if 'full-range' not in attr.checks:
2153                 continue                         2168                 continue
2154                                                  2169 
2155             if first:                            2170             if first:
2156                 cw.p('/* Integer value ranges    2171                 cw.p('/* Integer value ranges */')
2157                 first = False                    2172                 first = False
2158                                                  2173 
2159             sign = '' if attr.type[0] == 'u'     2174             sign = '' if attr.type[0] == 'u' else '_signed'
2160             suffix = 'ULL' if attr.type[0] ==    2175             suffix = 'ULL' if attr.type[0] == 'u' else 'LL'
2161             cw.block_start(line=f'static cons    2176             cw.block_start(line=f'static const struct netlink_range_validation{sign} {c_lower(attr.enum_name)}_range =')
2162             members = []                         2177             members = []
2163             if 'min' in attr.checks:             2178             if 'min' in attr.checks:
2164                 members.append(('min', str(at    2179                 members.append(('min', str(attr.get_limit('min')) + suffix))
2165             if 'max' in attr.checks:             2180             if 'max' in attr.checks:
2166                 members.append(('max', str(at    2181                 members.append(('max', str(attr.get_limit('max')) + suffix))
2167             cw.write_struct_init(members)        2182             cw.write_struct_init(members)
2168             cw.block_end(line=';')               2183             cw.block_end(line=';')
2169             cw.nl()                              2184             cw.nl()
2170                                                  2185 
2171                                                  2186 
2172 def print_kernel_op_table_fwd(family, cw, ter    2187 def print_kernel_op_table_fwd(family, cw, terminate):
2173     exported = not kernel_can_gen_family_stru    2188     exported = not kernel_can_gen_family_struct(family)
2174                                                  2189 
2175     if not terminate or exported:                2190     if not terminate or exported:
2176         cw.p(f"/* Ops table for {family.ident !! 2191         cw.p(f"/* Ops table for {family.name} */")
2177                                                  2192 
2178         pol_to_struct = {'global': 'genl_smal    2193         pol_to_struct = {'global': 'genl_small_ops',
2179                          'per-op': 'genl_ops'    2194                          'per-op': 'genl_ops',
2180                          'split': 'genl_split    2195                          'split': 'genl_split_ops'}
2181         struct_type = pol_to_struct[family.ke    2196         struct_type = pol_to_struct[family.kernel_policy]
2182                                                  2197 
2183         if not exported:                         2198         if not exported:
2184             cnt = ""                             2199             cnt = ""
2185         elif family.kernel_policy == 'split':    2200         elif family.kernel_policy == 'split':
2186             cnt = 0                              2201             cnt = 0
2187             for op in family.ops.values():       2202             for op in family.ops.values():
2188                 if 'do' in op:                   2203                 if 'do' in op:
2189                     cnt += 1                     2204                     cnt += 1
2190                 if 'dump' in op:                 2205                 if 'dump' in op:
2191                     cnt += 1                     2206                     cnt += 1
2192         else:                                    2207         else:
2193             cnt = len(family.ops)                2208             cnt = len(family.ops)
2194                                                  2209 
2195         qual = 'static const' if not exported    2210         qual = 'static const' if not exported else 'const'
2196         line = f"{qual} struct {struct_type}     2211         line = f"{qual} struct {struct_type} {family.c_name}_nl_ops[{cnt}]"
2197         if terminate:                            2212         if terminate:
2198             cw.p(f"extern {line};")              2213             cw.p(f"extern {line};")
2199         else:                                    2214         else:
2200             cw.block_start(line=line + ' =')     2215             cw.block_start(line=line + ' =')
2201                                                  2216 
2202     if not terminate:                            2217     if not terminate:
2203         return                                   2218         return
2204                                                  2219 
2205     cw.nl()                                      2220     cw.nl()
2206     for name in family.hooks['pre']['do']['li    2221     for name in family.hooks['pre']['do']['list']:
2207         cw.write_func_prot('int', c_lower(nam    2222         cw.write_func_prot('int', c_lower(name),
2208                            ['const struct gen    2223                            ['const struct genl_split_ops *ops',
2209                             'struct sk_buff *    2224                             'struct sk_buff *skb', 'struct genl_info *info'], suffix=';')
2210     for name in family.hooks['post']['do']['l    2225     for name in family.hooks['post']['do']['list']:
2211         cw.write_func_prot('void', c_lower(na    2226         cw.write_func_prot('void', c_lower(name),
2212                            ['const struct gen    2227                            ['const struct genl_split_ops *ops',
2213                             'struct sk_buff *    2228                             'struct sk_buff *skb', 'struct genl_info *info'], suffix=';')
2214     for name in family.hooks['pre']['dump']['    2229     for name in family.hooks['pre']['dump']['list']:
2215         cw.write_func_prot('int', c_lower(nam    2230         cw.write_func_prot('int', c_lower(name),
2216                            ['struct netlink_c    2231                            ['struct netlink_callback *cb'], suffix=';')
2217     for name in family.hooks['post']['dump'][    2232     for name in family.hooks['post']['dump']['list']:
2218         cw.write_func_prot('int', c_lower(nam    2233         cw.write_func_prot('int', c_lower(name),
2219                            ['struct netlink_c    2234                            ['struct netlink_callback *cb'], suffix=';')
2220                                                  2235 
2221     cw.nl()                                      2236     cw.nl()
2222                                                  2237 
2223     for op_name, op in family.ops.items():       2238     for op_name, op in family.ops.items():
2224         if op.is_async:                          2239         if op.is_async:
2225             continue                             2240             continue
2226                                                  2241 
2227         if 'do' in op:                           2242         if 'do' in op:
2228             name = c_lower(f"{family.ident_na !! 2243             name = c_lower(f"{family.name}-nl-{op_name}-doit")
2229             cw.write_func_prot('int', name,      2244             cw.write_func_prot('int', name,
2230                                ['struct sk_bu    2245                                ['struct sk_buff *skb', 'struct genl_info *info'], suffix=';')
2231                                                  2246 
2232         if 'dump' in op:                         2247         if 'dump' in op:
2233             name = c_lower(f"{family.ident_na !! 2248             name = c_lower(f"{family.name}-nl-{op_name}-dumpit")
2234             cw.write_func_prot('int', name,      2249             cw.write_func_prot('int', name,
2235                                ['struct sk_bu    2250                                ['struct sk_buff *skb', 'struct netlink_callback *cb'], suffix=';')
2236     cw.nl()                                      2251     cw.nl()
2237                                                  2252 
2238                                                  2253 
2239 def print_kernel_op_table_hdr(family, cw):       2254 def print_kernel_op_table_hdr(family, cw):
2240     print_kernel_op_table_fwd(family, cw, ter    2255     print_kernel_op_table_fwd(family, cw, terminate=True)
2241                                                  2256 
2242                                                  2257 
2243 def print_kernel_op_table(family, cw):           2258 def print_kernel_op_table(family, cw):
2244     print_kernel_op_table_fwd(family, cw, ter    2259     print_kernel_op_table_fwd(family, cw, terminate=False)
2245     if family.kernel_policy == 'global' or fa    2260     if family.kernel_policy == 'global' or family.kernel_policy == 'per-op':
2246         for op_name, op in family.ops.items()    2261         for op_name, op in family.ops.items():
2247             if op.is_async:                      2262             if op.is_async:
2248                 continue                         2263                 continue
2249                                                  2264 
2250             cw.ifdef_block(op.get('config-con    2265             cw.ifdef_block(op.get('config-cond', None))
2251             cw.block_start()                     2266             cw.block_start()
2252             members = [('cmd', op.enum_name)]    2267             members = [('cmd', op.enum_name)]
2253             if 'dont-validate' in op:            2268             if 'dont-validate' in op:
2254                 members.append(('validate',      2269                 members.append(('validate',
2255                                 ' | '.join([c    2270                                 ' | '.join([c_upper('genl-dont-validate-' + x)
2256                                             f    2271                                             for x in op['dont-validate']])), )
2257             for op_mode in ['do', 'dump']:       2272             for op_mode in ['do', 'dump']:
2258                 if op_mode in op:                2273                 if op_mode in op:
2259                     name = c_lower(f"{family. !! 2274                     name = c_lower(f"{family.name}-nl-{op_name}-{op_mode}it")
2260                     members.append((op_mode +    2275                     members.append((op_mode + 'it', name))
2261             if family.kernel_policy == 'per-o    2276             if family.kernel_policy == 'per-op':
2262                 struct = Struct(family, op['a    2277                 struct = Struct(family, op['attribute-set'],
2263                                 type_list=op[    2278                                 type_list=op['do']['request']['attributes'])
2264                                                  2279 
2265                 name = c_lower(f"{family.iden !! 2280                 name = c_lower(f"{family.name}-{op_name}-nl-policy")
2266                 members.append(('policy', nam    2281                 members.append(('policy', name))
2267                 members.append(('maxattr', st    2282                 members.append(('maxattr', struct.attr_max_val.enum_name))
2268             if 'flags' in op:                    2283             if 'flags' in op:
2269                 members.append(('flags', ' |     2284                 members.append(('flags', ' | '.join([c_upper('genl-' + x) for x in op['flags']])))
2270             cw.write_struct_init(members)        2285             cw.write_struct_init(members)
2271             cw.block_end(line=',')               2286             cw.block_end(line=',')
2272     elif family.kernel_policy == 'split':        2287     elif family.kernel_policy == 'split':
2273         cb_names = {'do':   {'pre': 'pre_doit    2288         cb_names = {'do':   {'pre': 'pre_doit', 'post': 'post_doit'},
2274                     'dump': {'pre': 'start',     2289                     'dump': {'pre': 'start', 'post': 'done'}}
2275                                                  2290 
2276         for op_name, op in family.ops.items()    2291         for op_name, op in family.ops.items():
2277             for op_mode in ['do', 'dump']:       2292             for op_mode in ['do', 'dump']:
2278                 if op.is_async or op_mode not    2293                 if op.is_async or op_mode not in op:
2279                     continue                     2294                     continue
2280                                                  2295 
2281                 cw.ifdef_block(op.get('config    2296                 cw.ifdef_block(op.get('config-cond', None))
2282                 cw.block_start()                 2297                 cw.block_start()
2283                 members = [('cmd', op.enum_na    2298                 members = [('cmd', op.enum_name)]
2284                 if 'dont-validate' in op:        2299                 if 'dont-validate' in op:
2285                     dont_validate = []           2300                     dont_validate = []
2286                     for x in op['dont-validat    2301                     for x in op['dont-validate']:
2287                         if op_mode == 'do' an    2302                         if op_mode == 'do' and x in ['dump', 'dump-strict']:
2288                             continue             2303                             continue
2289                         if op_mode == "dump"     2304                         if op_mode == "dump" and x == 'strict':
2290                             continue             2305                             continue
2291                         dont_validate.append(    2306                         dont_validate.append(x)
2292                                                  2307 
2293                     if dont_validate:            2308                     if dont_validate:
2294                         members.append(('vali    2309                         members.append(('validate',
2295                                         ' | '    2310                                         ' | '.join([c_upper('genl-dont-validate-' + x)
2296                                                  2311                                                     for x in dont_validate])), )
2297                 name = c_lower(f"{family.iden !! 2312                 name = c_lower(f"{family.name}-nl-{op_name}-{op_mode}it")
2298                 if 'pre' in op[op_mode]:         2313                 if 'pre' in op[op_mode]:
2299                     members.append((cb_names[    2314                     members.append((cb_names[op_mode]['pre'], c_lower(op[op_mode]['pre'])))
2300                 members.append((op_mode + 'it    2315                 members.append((op_mode + 'it', name))
2301                 if 'post' in op[op_mode]:        2316                 if 'post' in op[op_mode]:
2302                     members.append((cb_names[    2317                     members.append((cb_names[op_mode]['post'], c_lower(op[op_mode]['post'])))
2303                 if 'request' in op[op_mode]:     2318                 if 'request' in op[op_mode]:
2304                     struct = Struct(family, o    2319                     struct = Struct(family, op['attribute-set'],
2305                                     type_list    2320                                     type_list=op[op_mode]['request']['attributes'])
2306                                                  2321 
2307                     if op.dual_policy:           2322                     if op.dual_policy:
2308                         name = c_lower(f"{fam !! 2323                         name = c_lower(f"{family.name}-{op_name}-{op_mode}-nl-policy")
2309                     else:                        2324                     else:
2310                         name = c_lower(f"{fam !! 2325                         name = c_lower(f"{family.name}-{op_name}-nl-policy")
2311                     members.append(('policy',    2326                     members.append(('policy', name))
2312                     members.append(('maxattr'    2327                     members.append(('maxattr', struct.attr_max_val.enum_name))
2313                 flags = (op['flags'] if 'flag    2328                 flags = (op['flags'] if 'flags' in op else []) + ['cmd-cap-' + op_mode]
2314                 members.append(('flags', ' |     2329                 members.append(('flags', ' | '.join([c_upper('genl-' + x) for x in flags])))
2315                 cw.write_struct_init(members)    2330                 cw.write_struct_init(members)
2316                 cw.block_end(line=',')           2331                 cw.block_end(line=',')
2317     cw.ifdef_block(None)                         2332     cw.ifdef_block(None)
2318                                                  2333 
2319     cw.block_end(line=';')                       2334     cw.block_end(line=';')
2320     cw.nl()                                      2335     cw.nl()
2321                                                  2336 
2322                                                  2337 
2323 def print_kernel_mcgrp_hdr(family, cw):          2338 def print_kernel_mcgrp_hdr(family, cw):
2324     if not family.mcgrps['list']:                2339     if not family.mcgrps['list']:
2325         return                                   2340         return
2326                                                  2341 
2327     cw.block_start('enum')                       2342     cw.block_start('enum')
2328     for grp in family.mcgrps['list']:            2343     for grp in family.mcgrps['list']:
2329         grp_id = c_upper(f"{family.ident_name !! 2344         grp_id = c_upper(f"{family.name}-nlgrp-{grp['name']},")
2330         cw.p(grp_id)                             2345         cw.p(grp_id)
2331     cw.block_end(';')                            2346     cw.block_end(';')
2332     cw.nl()                                      2347     cw.nl()
2333                                                  2348 
2334                                                  2349 
2335 def print_kernel_mcgrp_src(family, cw):          2350 def print_kernel_mcgrp_src(family, cw):
2336     if not family.mcgrps['list']:                2351     if not family.mcgrps['list']:
2337         return                                   2352         return
2338                                                  2353 
2339     cw.block_start('static const struct genl_    2354     cw.block_start('static const struct genl_multicast_group ' + family.c_name + '_nl_mcgrps[] =')
2340     for grp in family.mcgrps['list']:            2355     for grp in family.mcgrps['list']:
2341         name = grp['name']                       2356         name = grp['name']
2342         grp_id = c_upper(f"{family.ident_name !! 2357         grp_id = c_upper(f"{family.name}-nlgrp-{name}")
2343         cw.p('[' + grp_id + '] = { "' + name     2358         cw.p('[' + grp_id + '] = { "' + name + '", },')
2344     cw.block_end(';')                            2359     cw.block_end(';')
2345     cw.nl()                                      2360     cw.nl()
2346                                                  2361 
2347                                                  2362 
2348 def print_kernel_family_struct_hdr(family, cw    2363 def print_kernel_family_struct_hdr(family, cw):
2349     if not kernel_can_gen_family_struct(famil    2364     if not kernel_can_gen_family_struct(family):
2350         return                                   2365         return
2351                                                  2366 
2352     cw.p(f"extern struct genl_family {family.    2367     cw.p(f"extern struct genl_family {family.c_name}_nl_family;")
2353     cw.nl()                                      2368     cw.nl()
2354     if 'sock-priv' in family.kernel_family:   << 
2355         cw.p(f'void {family.c_name}_nl_sock_p << 
2356         cw.p(f'void {family.c_name}_nl_sock_p << 
2357         cw.nl()                               << 
2358                                                  2369 
2359                                                  2370 
2360 def print_kernel_family_struct_src(family, cw    2371 def print_kernel_family_struct_src(family, cw):
2361     if not kernel_can_gen_family_struct(famil    2372     if not kernel_can_gen_family_struct(family):
2362         return                                   2373         return
2363                                                  2374 
2364     cw.block_start(f"struct genl_family {fami !! 2375     cw.block_start(f"struct genl_family {family.name}_nl_family __ro_after_init =")
2365     cw.p('.name\t\t= ' + family.fam_key + ','    2376     cw.p('.name\t\t= ' + family.fam_key + ',')
2366     cw.p('.version\t= ' + family.ver_key + ',    2377     cw.p('.version\t= ' + family.ver_key + ',')
2367     cw.p('.netnsok\t= true,')                    2378     cw.p('.netnsok\t= true,')
2368     cw.p('.parallel_ops\t= true,')               2379     cw.p('.parallel_ops\t= true,')
2369     cw.p('.module\t\t= THIS_MODULE,')            2380     cw.p('.module\t\t= THIS_MODULE,')
2370     if family.kernel_policy == 'per-op':         2381     if family.kernel_policy == 'per-op':
2371         cw.p(f'.ops\t\t= {family.c_name}_nl_o    2382         cw.p(f'.ops\t\t= {family.c_name}_nl_ops,')
2372         cw.p(f'.n_ops\t\t= ARRAY_SIZE({family    2383         cw.p(f'.n_ops\t\t= ARRAY_SIZE({family.c_name}_nl_ops),')
2373     elif family.kernel_policy == 'split':        2384     elif family.kernel_policy == 'split':
2374         cw.p(f'.split_ops\t= {family.c_name}_    2385         cw.p(f'.split_ops\t= {family.c_name}_nl_ops,')
2375         cw.p(f'.n_split_ops\t= ARRAY_SIZE({fa    2386         cw.p(f'.n_split_ops\t= ARRAY_SIZE({family.c_name}_nl_ops),')
2376     if family.mcgrps['list']:                    2387     if family.mcgrps['list']:
2377         cw.p(f'.mcgrps\t\t= {family.c_name}_n    2388         cw.p(f'.mcgrps\t\t= {family.c_name}_nl_mcgrps,')
2378         cw.p(f'.n_mcgrps\t= ARRAY_SIZE({famil    2389         cw.p(f'.n_mcgrps\t= ARRAY_SIZE({family.c_name}_nl_mcgrps),')
2379     if 'sock-priv' in family.kernel_family:   << 
2380         cw.p(f'.sock_priv_size\t= sizeof({fam << 
2381         # Force cast here, actual helpers tak << 
2382         cw.p(f'.sock_priv_init\t= (void *){fa << 
2383         cw.p(f'.sock_priv_destroy = (void *){ << 
2384     cw.block_end(';')                            2390     cw.block_end(';')
2385                                                  2391 
2386                                                  2392 
2387 def uapi_enum_start(family, cw, obj, ckey='',    2393 def uapi_enum_start(family, cw, obj, ckey='', enum_name='enum-name'):
2388     start_line = 'enum'                          2394     start_line = 'enum'
2389     if enum_name in obj:                         2395     if enum_name in obj:
2390         if obj[enum_name]:                       2396         if obj[enum_name]:
2391             start_line = 'enum ' + c_lower(ob    2397             start_line = 'enum ' + c_lower(obj[enum_name])
2392     elif ckey and ckey in obj:                   2398     elif ckey and ckey in obj:
2393         start_line = 'enum ' + family.c_name     2399         start_line = 'enum ' + family.c_name + '_' + c_lower(obj[ckey])
2394     cw.block_start(line=start_line)              2400     cw.block_start(line=start_line)
2395                                                  2401 
2396                                                  2402 
2397 def render_uapi(family, cw):                     2403 def render_uapi(family, cw):
2398     hdr_prot = f"_UAPI_LINUX_{c_upper(family.    2404     hdr_prot = f"_UAPI_LINUX_{c_upper(family.uapi_header_name)}_H"
2399     cw.p('#ifndef ' + hdr_prot)                  2405     cw.p('#ifndef ' + hdr_prot)
2400     cw.p('#define ' + hdr_prot)                  2406     cw.p('#define ' + hdr_prot)
2401     cw.nl()                                      2407     cw.nl()
2402                                                  2408 
2403     defines = [(family.fam_key, family["name"    2409     defines = [(family.fam_key, family["name"]),
2404                (family.ver_key, family.get('v    2410                (family.ver_key, family.get('version', 1))]
2405     cw.writes_defines(defines)                   2411     cw.writes_defines(defines)
2406     cw.nl()                                      2412     cw.nl()
2407                                                  2413 
2408     defines = []                                 2414     defines = []
2409     for const in family['definitions']:          2415     for const in family['definitions']:
2410         if const['type'] != 'const':             2416         if const['type'] != 'const':
2411             cw.writes_defines(defines)           2417             cw.writes_defines(defines)
2412             defines = []                         2418             defines = []
2413             cw.nl()                              2419             cw.nl()
2414                                                  2420 
2415         # Write kdoc for enum and flags (one     2421         # Write kdoc for enum and flags (one day maybe also structs)
2416         if const['type'] == 'enum' or const['    2422         if const['type'] == 'enum' or const['type'] == 'flags':
2417             enum = family.consts[const['name'    2423             enum = family.consts[const['name']]
2418                                                  2424 
2419             if enum.has_doc():                   2425             if enum.has_doc():
2420                 cw.p('/**')                      2426                 cw.p('/**')
2421                 doc = ''                         2427                 doc = ''
2422                 if 'doc' in enum:                2428                 if 'doc' in enum:
2423                     doc = ' - ' + enum['doc']    2429                     doc = ' - ' + enum['doc']
2424                 cw.write_doc_line(enum.enum_n    2430                 cw.write_doc_line(enum.enum_name + doc)
2425                 for entry in enum.entries.val    2431                 for entry in enum.entries.values():
2426                     if entry.has_doc():          2432                     if entry.has_doc():
2427                         doc = '@' + entry.c_n    2433                         doc = '@' + entry.c_name + ': ' + entry['doc']
2428                         cw.write_doc_line(doc    2434                         cw.write_doc_line(doc)
2429                 cw.p(' */')                      2435                 cw.p(' */')
2430                                                  2436 
2431             uapi_enum_start(family, cw, const    2437             uapi_enum_start(family, cw, const, 'name')
2432             name_pfx = const.get('name-prefix !! 2438             name_pfx = const.get('name-prefix', f"{family.name}-{const['name']}-")
2433             for entry in enum.entries.values(    2439             for entry in enum.entries.values():
2434                 suffix = ','                     2440                 suffix = ','
2435                 if entry.value_change:           2441                 if entry.value_change:
2436                     suffix = f" = {entry.user    2442                     suffix = f" = {entry.user_value()}" + suffix
2437                 cw.p(entry.c_name + suffix)      2443                 cw.p(entry.c_name + suffix)
2438                                                  2444 
2439             if const.get('render-max', False)    2445             if const.get('render-max', False):
2440                 cw.nl()                          2446                 cw.nl()
2441                 cw.p('/* private: */')           2447                 cw.p('/* private: */')
2442                 if const['type'] == 'flags':     2448                 if const['type'] == 'flags':
2443                     max_name = c_upper(name_p    2449                     max_name = c_upper(name_pfx + 'mask')
2444                     max_val = f' = {enum.get_    2450                     max_val = f' = {enum.get_mask()},'
2445                     cw.p(max_name + max_val)     2451                     cw.p(max_name + max_val)
2446                 else:                            2452                 else:
2447                     max_name = c_upper(name_p    2453                     max_name = c_upper(name_pfx + 'max')
2448                     cw.p('__' + max_name + ',    2454                     cw.p('__' + max_name + ',')
2449                     cw.p(max_name + ' = (__'     2455                     cw.p(max_name + ' = (__' + max_name + ' - 1)')
2450             cw.block_end(line=';')               2456             cw.block_end(line=';')
2451             cw.nl()                              2457             cw.nl()
2452         elif const['type'] == 'const':           2458         elif const['type'] == 'const':
2453             defines.append([c_upper(family.ge    2459             defines.append([c_upper(family.get('c-define-name',
2454                                               !! 2460                                                f"{family.name}-{const['name']}")),
2455                             const['value']])     2461                             const['value']])
2456                                                  2462 
2457     if defines:                                  2463     if defines:
2458         cw.writes_defines(defines)               2464         cw.writes_defines(defines)
2459         cw.nl()                                  2465         cw.nl()
2460                                                  2466 
2461     max_by_define = family.get('max-by-define    2467     max_by_define = family.get('max-by-define', False)
2462                                                  2468 
2463     for _, attr_set in family.attr_sets.items    2469     for _, attr_set in family.attr_sets.items():
2464         if attr_set.subset_of:                   2470         if attr_set.subset_of:
2465             continue                             2471             continue
2466                                                  2472 
2467         max_value = f"({attr_set.cnt_name} -     2473         max_value = f"({attr_set.cnt_name} - 1)"
2468                                                  2474 
2469         val = 0                                  2475         val = 0
2470         uapi_enum_start(family, cw, attr_set.    2476         uapi_enum_start(family, cw, attr_set.yaml, 'enum-name')
2471         for _, attr in attr_set.items():         2477         for _, attr in attr_set.items():
2472             suffix = ','                         2478             suffix = ','
2473             if attr.value != val:                2479             if attr.value != val:
2474                 suffix = f" = {attr.value},"     2480                 suffix = f" = {attr.value},"
2475                 val = attr.value                 2481                 val = attr.value
2476             val += 1                             2482             val += 1
2477             cw.p(attr.enum_name + suffix)        2483             cw.p(attr.enum_name + suffix)
2478         cw.nl()                                  2484         cw.nl()
2479         cw.p(attr_set.cnt_name + ('' if max_b    2485         cw.p(attr_set.cnt_name + ('' if max_by_define else ','))
2480         if not max_by_define:                    2486         if not max_by_define:
2481             cw.p(f"{attr_set.max_name} = {max    2487             cw.p(f"{attr_set.max_name} = {max_value}")
2482         cw.block_end(line=';')                   2488         cw.block_end(line=';')
2483         if max_by_define:                        2489         if max_by_define:
2484             cw.p(f"#define {attr_set.max_name    2490             cw.p(f"#define {attr_set.max_name} {max_value}")
2485         cw.nl()                                  2491         cw.nl()
2486                                                  2492 
2487     # Commands                                   2493     # Commands
2488     separate_ntf = 'async-prefix' in family['    2494     separate_ntf = 'async-prefix' in family['operations']
2489                                                  2495 
2490     max_name = c_upper(family.get('cmd-max-na    2496     max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX"))
2491     cnt_name = c_upper(family.get('cmd-cnt-na    2497     cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX"))
2492     max_value = f"({cnt_name} - 1)"              2498     max_value = f"({cnt_name} - 1)"
2493                                                  2499 
2494     uapi_enum_start(family, cw, family['opera    2500     uapi_enum_start(family, cw, family['operations'], 'enum-name')
2495     val = 0                                      2501     val = 0
2496     for op in family.msgs.values():              2502     for op in family.msgs.values():
2497         if separate_ntf and ('notify' in op o    2503         if separate_ntf and ('notify' in op or 'event' in op):
2498             continue                             2504             continue
2499                                                  2505 
2500         suffix = ','                             2506         suffix = ','
2501         if op.value != val:                      2507         if op.value != val:
2502             suffix = f" = {op.value},"           2508             suffix = f" = {op.value},"
2503             val = op.value                       2509             val = op.value
2504         cw.p(op.enum_name + suffix)              2510         cw.p(op.enum_name + suffix)
2505         val += 1                                 2511         val += 1
2506     cw.nl()                                      2512     cw.nl()
2507     cw.p(cnt_name + ('' if max_by_define else    2513     cw.p(cnt_name + ('' if max_by_define else ','))
2508     if not max_by_define:                        2514     if not max_by_define:
2509         cw.p(f"{max_name} = {max_value}")        2515         cw.p(f"{max_name} = {max_value}")
2510     cw.block_end(line=';')                       2516     cw.block_end(line=';')
2511     if max_by_define:                            2517     if max_by_define:
2512         cw.p(f"#define {max_name} {max_value}    2518         cw.p(f"#define {max_name} {max_value}")
2513     cw.nl()                                      2519     cw.nl()
2514                                                  2520 
2515     if separate_ntf:                             2521     if separate_ntf:
2516         uapi_enum_start(family, cw, family['o    2522         uapi_enum_start(family, cw, family['operations'], enum_name='async-enum')
2517         for op in family.msgs.values():          2523         for op in family.msgs.values():
2518             if separate_ntf and not ('notify'    2524             if separate_ntf and not ('notify' in op or 'event' in op):
2519                 continue                         2525                 continue
2520                                                  2526 
2521             suffix = ','                         2527             suffix = ','
2522             if 'value' in op:                    2528             if 'value' in op:
2523                 suffix = f" = {op['value']},"    2529                 suffix = f" = {op['value']},"
2524             cw.p(op.enum_name + suffix)          2530             cw.p(op.enum_name + suffix)
2525         cw.block_end(line=';')                   2531         cw.block_end(line=';')
2526         cw.nl()                                  2532         cw.nl()
2527                                                  2533 
2528     # Multicast                                  2534     # Multicast
2529     defines = []                                 2535     defines = []
2530     for grp in family.mcgrps['list']:            2536     for grp in family.mcgrps['list']:
2531         name = grp['name']                       2537         name = grp['name']
2532         defines.append([c_upper(grp.get('c-de !! 2538         defines.append([c_upper(grp.get('c-define-name', f"{family.name}-mcgrp-{name}")),
2533                         f'{name}'])              2539                         f'{name}'])
2534     cw.nl()                                      2540     cw.nl()
2535     if defines:                                  2541     if defines:
2536         cw.writes_defines(defines)               2542         cw.writes_defines(defines)
2537         cw.nl()                                  2543         cw.nl()
2538                                                  2544 
2539     cw.p(f'#endif /* {hdr_prot} */')             2545     cw.p(f'#endif /* {hdr_prot} */')
2540                                                  2546 
2541                                                  2547 
2542 def _render_user_ntf_entry(ri, op):              2548 def _render_user_ntf_entry(ri, op):
2543     ri.cw.block_start(line=f"[{op.enum_name}]    2549     ri.cw.block_start(line=f"[{op.enum_name}] = ")
2544     ri.cw.p(f".alloc_sz\t= sizeof({type_name(    2550     ri.cw.p(f".alloc_sz\t= sizeof({type_name(ri, 'event')}),")
2545     ri.cw.p(f".cb\t\t= {op_prefix(ri, 'reply'    2551     ri.cw.p(f".cb\t\t= {op_prefix(ri, 'reply', deref=True)}_parse,")
2546     ri.cw.p(f".policy\t\t= &{ri.struct['reply    2552     ri.cw.p(f".policy\t\t= &{ri.struct['reply'].render_name}_nest,")
2547     ri.cw.p(f".free\t\t= (void *){op_prefix(r    2553     ri.cw.p(f".free\t\t= (void *){op_prefix(ri, 'notify')}_free,")
2548     ri.cw.block_end(line=',')                    2554     ri.cw.block_end(line=',')
2549                                                  2555 
2550                                                  2556 
2551 def render_user_family(family, cw, prototype)    2557 def render_user_family(family, cw, prototype):
2552     symbol = f'const struct ynl_family ynl_{f    2558     symbol = f'const struct ynl_family ynl_{family.c_name}_family'
2553     if prototype:                                2559     if prototype:
2554         cw.p(f'extern {symbol};')                2560         cw.p(f'extern {symbol};')
2555         return                                   2561         return
2556                                                  2562 
2557     if family.ntfs:                              2563     if family.ntfs:
2558         cw.block_start(line=f"static const st    2564         cw.block_start(line=f"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ")
2559         for ntf_op_name, ntf_op in family.ntf    2565         for ntf_op_name, ntf_op in family.ntfs.items():
2560             if 'notify' in ntf_op:               2566             if 'notify' in ntf_op:
2561                 op = family.ops[ntf_op['notif    2567                 op = family.ops[ntf_op['notify']]
2562                 ri = RenderInfo(cw, family, "    2568                 ri = RenderInfo(cw, family, "user", op, "notify")
2563             elif 'event' in ntf_op:              2569             elif 'event' in ntf_op:
2564                 ri = RenderInfo(cw, family, "    2570                 ri = RenderInfo(cw, family, "user", ntf_op, "event")
2565             else:                                2571             else:
2566                 raise Exception('Invalid noti    2572                 raise Exception('Invalid notification ' + ntf_op_name)
2567             _render_user_ntf_entry(ri, ntf_op    2573             _render_user_ntf_entry(ri, ntf_op)
2568         for op_name, op in family.ops.items()    2574         for op_name, op in family.ops.items():
2569             if 'event' not in op:                2575             if 'event' not in op:
2570                 continue                         2576                 continue
2571             ri = RenderInfo(cw, family, "user    2577             ri = RenderInfo(cw, family, "user", op, "event")
2572             _render_user_ntf_entry(ri, op)       2578             _render_user_ntf_entry(ri, op)
2573         cw.block_end(line=";")                   2579         cw.block_end(line=";")
2574         cw.nl()                                  2580         cw.nl()
2575                                                  2581 
2576     cw.block_start(f'{symbol} = ')               2582     cw.block_start(f'{symbol} = ')
2577     cw.p(f'.name\t\t= "{family.c_name}",')       2583     cw.p(f'.name\t\t= "{family.c_name}",')
2578     if family.fixed_header:                      2584     if family.fixed_header:
2579         cw.p(f'.hdr_len\t= sizeof(struct genl    2585         cw.p(f'.hdr_len\t= sizeof(struct genlmsghdr) + sizeof(struct {c_lower(family.fixed_header)}),')
2580     else:                                        2586     else:
2581         cw.p('.hdr_len\t= sizeof(struct genlm    2587         cw.p('.hdr_len\t= sizeof(struct genlmsghdr),')
2582     if family.ntfs:                              2588     if family.ntfs:
2583         cw.p(f".ntf_info\t= {family['name']}_    2589         cw.p(f".ntf_info\t= {family['name']}_ntf_info,")
2584         cw.p(f".ntf_info_size\t= YNL_ARRAY_SI !! 2590         cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),")
2585     cw.block_end(line=';')                       2591     cw.block_end(line=';')
2586                                                  2592 
2587                                                  2593 
2588 def family_contains_bitfield32(family):          2594 def family_contains_bitfield32(family):
2589     for _, attr_set in family.attr_sets.items    2595     for _, attr_set in family.attr_sets.items():
2590         if attr_set.subset_of:                   2596         if attr_set.subset_of:
2591             continue                             2597             continue
2592         for _, attr in attr_set.items():         2598         for _, attr in attr_set.items():
2593             if attr.type == "bitfield32":        2599             if attr.type == "bitfield32":
2594                 return True                      2600                 return True
2595     return False                                 2601     return False
2596                                                  2602 
2597                                                  2603 
2598 def find_kernel_root(full_path):                 2604 def find_kernel_root(full_path):
2599     sub_path = ''                                2605     sub_path = ''
2600     while True:                                  2606     while True:
2601         sub_path = os.path.join(os.path.basen    2607         sub_path = os.path.join(os.path.basename(full_path), sub_path)
2602         full_path = os.path.dirname(full_path    2608         full_path = os.path.dirname(full_path)
2603         maintainers = os.path.join(full_path,    2609         maintainers = os.path.join(full_path, "MAINTAINERS")
2604         if os.path.exists(maintainers):          2610         if os.path.exists(maintainers):
2605             return full_path, sub_path[:-1]      2611             return full_path, sub_path[:-1]
2606                                                  2612 
2607                                                  2613 
2608 def main():                                      2614 def main():
2609     parser = argparse.ArgumentParser(descript    2615     parser = argparse.ArgumentParser(description='Netlink simple parsing generator')
2610     parser.add_argument('--mode', dest='mode'    2616     parser.add_argument('--mode', dest='mode', type=str, required=True)
2611     parser.add_argument('--spec', dest='spec'    2617     parser.add_argument('--spec', dest='spec', type=str, required=True)
2612     parser.add_argument('--header', dest='hea    2618     parser.add_argument('--header', dest='header', action='store_true', default=None)
2613     parser.add_argument('--source', dest='hea    2619     parser.add_argument('--source', dest='header', action='store_false')
2614     parser.add_argument('--user-header', narg    2620     parser.add_argument('--user-header', nargs='+', default=[])
2615     parser.add_argument('--cmp-out', action='    2621     parser.add_argument('--cmp-out', action='store_true', default=None,
2616                         help='Do not overwrit    2622                         help='Do not overwrite the output file if the new output is identical to the old')
2617     parser.add_argument('--exclude-op', actio    2623     parser.add_argument('--exclude-op', action='append', default=[])
2618     parser.add_argument('-o', dest='out_file'    2624     parser.add_argument('-o', dest='out_file', type=str, default=None)
2619     args = parser.parse_args()                   2625     args = parser.parse_args()
2620                                                  2626 
2621     if args.header is None:                      2627     if args.header is None:
2622         parser.error("--header or --source is    2628         parser.error("--header or --source is required")
2623                                                  2629 
2624     exclude_ops = [re.compile(expr) for expr     2630     exclude_ops = [re.compile(expr) for expr in args.exclude_op]
2625                                                  2631 
2626     try:                                         2632     try:
2627         parsed = Family(args.spec, exclude_op    2633         parsed = Family(args.spec, exclude_ops)
2628         if parsed.license != '((GPL-2.0 WITH     2634         if parsed.license != '((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)':
2629             print('Spec license:', parsed.lic    2635             print('Spec license:', parsed.license)
2630             print('License must be: ((GPL-2.0    2636             print('License must be: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)')
2631             os.sys.exit(1)                       2637             os.sys.exit(1)
2632     except yaml.YAMLError as exc:                2638     except yaml.YAMLError as exc:
2633         print(exc)                               2639         print(exc)
2634         os.sys.exit(1)                           2640         os.sys.exit(1)
2635         return                                   2641         return
2636                                                  2642 
2637     supported_models = ['unified']               2643     supported_models = ['unified']
2638     if args.mode in ['user', 'kernel']:          2644     if args.mode in ['user', 'kernel']:
2639         supported_models += ['directional']      2645         supported_models += ['directional']
2640     if parsed.msg_id_model not in supported_m    2646     if parsed.msg_id_model not in supported_models:
2641         print(f'Message enum-model {parsed.ms    2647         print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation')
2642         os.sys.exit(1)                           2648         os.sys.exit(1)
2643                                                  2649 
2644     cw = CodeWriter(BaseNlLib(), args.out_fil    2650     cw = CodeWriter(BaseNlLib(), args.out_file, overwrite=(not args.cmp_out))
2645                                                  2651 
2646     _, spec_kernel = find_kernel_root(args.sp    2652     _, spec_kernel = find_kernel_root(args.spec)
2647     if args.mode == 'uapi' or args.header:       2653     if args.mode == 'uapi' or args.header:
2648         cw.p(f'/* SPDX-License-Identifier: {p    2654         cw.p(f'/* SPDX-License-Identifier: {parsed.license} */')
2649     else:                                        2655     else:
2650         cw.p(f'// SPDX-License-Identifier: {p    2656         cw.p(f'// SPDX-License-Identifier: {parsed.license}')
2651     cw.p("/* Do not edit directly, auto-gener    2657     cw.p("/* Do not edit directly, auto-generated from: */")
2652     cw.p(f"/*\t{spec_kernel} */")                2658     cw.p(f"/*\t{spec_kernel} */")
2653     cw.p(f"/* YNL-GEN {args.mode} {'header' i    2659     cw.p(f"/* YNL-GEN {args.mode} {'header' if args.header else 'source'} */")
2654     if args.exclude_op or args.user_header:      2660     if args.exclude_op or args.user_header:
2655         line = ''                                2661         line = ''
2656         line += ' --user-header '.join([''] +    2662         line += ' --user-header '.join([''] + args.user_header)
2657         line += ' --exclude-op '.join([''] +     2663         line += ' --exclude-op '.join([''] + args.exclude_op)
2658         cw.p(f'/* YNL-ARG{line} */')             2664         cw.p(f'/* YNL-ARG{line} */')
2659     cw.nl()                                      2665     cw.nl()
2660                                                  2666 
2661     if args.mode == 'uapi':                      2667     if args.mode == 'uapi':
2662         render_uapi(parsed, cw)                  2668         render_uapi(parsed, cw)
2663         return                                   2669         return
2664                                                  2670 
2665     hdr_prot = f"_LINUX_{parsed.c_name.upper(    2671     hdr_prot = f"_LINUX_{parsed.c_name.upper()}_GEN_H"
2666     if args.header:                              2672     if args.header:
2667         cw.p('#ifndef ' + hdr_prot)              2673         cw.p('#ifndef ' + hdr_prot)
2668         cw.p('#define ' + hdr_prot)              2674         cw.p('#define ' + hdr_prot)
2669         cw.nl()                                  2675         cw.nl()
2670                                                  2676 
2671     hdr_file=os.path.basename(args.out_file[: << 
2672                                               << 
2673     if args.mode == 'kernel':                    2677     if args.mode == 'kernel':
2674         cw.p('#include <net/netlink.h>')         2678         cw.p('#include <net/netlink.h>')
2675         cw.p('#include <net/genetlink.h>')       2679         cw.p('#include <net/genetlink.h>')
2676         cw.nl()                                  2680         cw.nl()
2677         if not args.header:                      2681         if not args.header:
2678             if args.out_file:                    2682             if args.out_file:
2679                 cw.p(f'#include "{hdr_file}"' !! 2683                 cw.p(f'#include "{os.path.basename(args.out_file[:-2])}.h"')
2680             cw.nl()                              2684             cw.nl()
2681         headers = ['uapi/' + parsed.uapi_head    2685         headers = ['uapi/' + parsed.uapi_header]
2682         headers += parsed.kernel_family.get(' << 
2683     else:                                        2686     else:
2684         cw.p('#include <stdlib.h>')              2687         cw.p('#include <stdlib.h>')
2685         cw.p('#include <string.h>')              2688         cw.p('#include <string.h>')
2686         if args.header:                          2689         if args.header:
2687             cw.p('#include <linux/types.h>')     2690             cw.p('#include <linux/types.h>')
2688             if family_contains_bitfield32(par    2691             if family_contains_bitfield32(parsed):
2689                 cw.p('#include <linux/netlink    2692                 cw.p('#include <linux/netlink.h>')
2690         else:                                    2693         else:
2691             cw.p(f'#include "{hdr_file}"')    !! 2694             cw.p(f'#include "{parsed.name}-user.h"')
2692             cw.p('#include "ynl.h"')             2695             cw.p('#include "ynl.h"')
2693         headers = [parsed.uapi_header]           2696         headers = [parsed.uapi_header]
2694     for definition in parsed['definitions']:     2697     for definition in parsed['definitions']:
2695         if 'header' in definition:               2698         if 'header' in definition:
2696             headers.append(definition['header    2699             headers.append(definition['header'])
2697     for one in headers:                          2700     for one in headers:
2698         cw.p(f"#include <{one}>")                2701         cw.p(f"#include <{one}>")
2699     cw.nl()                                      2702     cw.nl()
2700                                                  2703 
2701     if args.mode == "user":                      2704     if args.mode == "user":
2702         if not args.header:                      2705         if not args.header:
                                                   >> 2706             cw.p("#include <libmnl/libmnl.h>")
2703             cw.p("#include <linux/genetlink.h    2707             cw.p("#include <linux/genetlink.h>")
2704             cw.nl()                              2708             cw.nl()
2705             for one in args.user_header:         2709             for one in args.user_header:
2706                 cw.p(f'#include "{one}"')        2710                 cw.p(f'#include "{one}"')
2707         else:                                    2711         else:
2708             cw.p('struct ynl_sock;')             2712             cw.p('struct ynl_sock;')
2709             cw.nl()                              2713             cw.nl()
2710             render_user_family(parsed, cw, Tr    2714             render_user_family(parsed, cw, True)
2711         cw.nl()                                  2715         cw.nl()
2712                                                  2716 
2713     if args.mode == "kernel":                    2717     if args.mode == "kernel":
2714         if args.header:                          2718         if args.header:
2715             for _, struct in sorted(parsed.pu    2719             for _, struct in sorted(parsed.pure_nested_structs.items()):
2716                 if struct.request:               2720                 if struct.request:
2717                     cw.p('/* Common nested ty    2721                     cw.p('/* Common nested types */')
2718                     break                        2722                     break
2719             for attr_set, struct in sorted(pa    2723             for attr_set, struct in sorted(parsed.pure_nested_structs.items()):
2720                 if struct.request:               2724                 if struct.request:
2721                     print_req_policy_fwd(cw,     2725                     print_req_policy_fwd(cw, struct)
2722             cw.nl()                              2726             cw.nl()
2723                                                  2727 
2724             if parsed.kernel_policy == 'globa    2728             if parsed.kernel_policy == 'global':
2725                 cw.p(f"/* Global operation po    2729                 cw.p(f"/* Global operation policy for {parsed.name} */")
2726                                                  2730 
2727                 struct = Struct(parsed, parse    2731                 struct = Struct(parsed, parsed.global_policy_set, type_list=parsed.global_policy)
2728                 print_req_policy_fwd(cw, stru    2732                 print_req_policy_fwd(cw, struct)
2729                 cw.nl()                          2733                 cw.nl()
2730                                                  2734 
2731             if parsed.kernel_policy in {'per-    2735             if parsed.kernel_policy in {'per-op', 'split'}:
2732                 for op_name, op in parsed.ops    2736                 for op_name, op in parsed.ops.items():
2733                     if 'do' in op and 'event'    2737                     if 'do' in op and 'event' not in op:
2734                         ri = RenderInfo(cw, p    2738                         ri = RenderInfo(cw, parsed, args.mode, op, "do")
2735                         print_req_policy_fwd(    2739                         print_req_policy_fwd(cw, ri.struct['request'], ri=ri)
2736                         cw.nl()                  2740                         cw.nl()
2737                                                  2741 
2738             print_kernel_op_table_hdr(parsed,    2742             print_kernel_op_table_hdr(parsed, cw)
2739             print_kernel_mcgrp_hdr(parsed, cw    2743             print_kernel_mcgrp_hdr(parsed, cw)
2740             print_kernel_family_struct_hdr(pa    2744             print_kernel_family_struct_hdr(parsed, cw)
2741         else:                                    2745         else:
2742             print_kernel_policy_ranges(parsed    2746             print_kernel_policy_ranges(parsed, cw)
2743                                                  2747 
2744             for _, struct in sorted(parsed.pu    2748             for _, struct in sorted(parsed.pure_nested_structs.items()):
2745                 if struct.request:               2749                 if struct.request:
2746                     cw.p('/* Common nested ty    2750                     cw.p('/* Common nested types */')
2747                     break                        2751                     break
2748             for attr_set, struct in sorted(pa    2752             for attr_set, struct in sorted(parsed.pure_nested_structs.items()):
2749                 if struct.request:               2753                 if struct.request:
2750                     print_req_policy(cw, stru    2754                     print_req_policy(cw, struct)
2751             cw.nl()                              2755             cw.nl()
2752                                                  2756 
2753             if parsed.kernel_policy == 'globa    2757             if parsed.kernel_policy == 'global':
2754                 cw.p(f"/* Global operation po    2758                 cw.p(f"/* Global operation policy for {parsed.name} */")
2755                                                  2759 
2756                 struct = Struct(parsed, parse    2760                 struct = Struct(parsed, parsed.global_policy_set, type_list=parsed.global_policy)
2757                 print_req_policy(cw, struct)     2761                 print_req_policy(cw, struct)
2758                 cw.nl()                          2762                 cw.nl()
2759                                                  2763 
2760             for op_name, op in parsed.ops.ite    2764             for op_name, op in parsed.ops.items():
2761                 if parsed.kernel_policy in {'    2765                 if parsed.kernel_policy in {'per-op', 'split'}:
2762                     for op_mode in ['do', 'du    2766                     for op_mode in ['do', 'dump']:
2763                         if op_mode in op and     2767                         if op_mode in op and 'request' in op[op_mode]:
2764                             cw.p(f"/* {op.enu    2768                             cw.p(f"/* {op.enum_name} - {op_mode} */")
2765                             ri = RenderInfo(c    2769                             ri = RenderInfo(cw, parsed, args.mode, op, op_mode)
2766                             print_req_policy(    2770                             print_req_policy(cw, ri.struct['request'], ri=ri)
2767                             cw.nl()              2771                             cw.nl()
2768                                                  2772 
2769             print_kernel_op_table(parsed, cw)    2773             print_kernel_op_table(parsed, cw)
2770             print_kernel_mcgrp_src(parsed, cw    2774             print_kernel_mcgrp_src(parsed, cw)
2771             print_kernel_family_struct_src(pa    2775             print_kernel_family_struct_src(parsed, cw)
2772                                                  2776 
2773     if args.mode == "user":                      2777     if args.mode == "user":
2774         if args.header:                          2778         if args.header:
2775             cw.p('/* Enums */')                  2779             cw.p('/* Enums */')
2776             put_op_name_fwd(parsed, cw)          2780             put_op_name_fwd(parsed, cw)
2777                                                  2781 
2778             for name, const in parsed.consts.    2782             for name, const in parsed.consts.items():
2779                 if isinstance(const, EnumSet)    2783                 if isinstance(const, EnumSet):
2780                     put_enum_to_str_fwd(parse    2784                     put_enum_to_str_fwd(parsed, cw, const)
2781             cw.nl()                              2785             cw.nl()
2782                                                  2786 
2783             cw.p('/* Common nested types */')    2787             cw.p('/* Common nested types */')
2784             for attr_set, struct in parsed.pu    2788             for attr_set, struct in parsed.pure_nested_structs.items():
2785                 ri = RenderInfo(cw, parsed, a    2789                 ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set)
2786                 print_type_full(ri, struct)      2790                 print_type_full(ri, struct)
2787                                                  2791 
2788             for op_name, op in parsed.ops.ite    2792             for op_name, op in parsed.ops.items():
2789                 cw.p(f"/* ============== {op.    2793                 cw.p(f"/* ============== {op.enum_name} ============== */")
2790                                                  2794 
2791                 if 'do' in op and 'event' not    2795                 if 'do' in op and 'event' not in op:
2792                     cw.p(f"/* {op.enum_name}     2796                     cw.p(f"/* {op.enum_name} - do */")
2793                     ri = RenderInfo(cw, parse    2797                     ri = RenderInfo(cw, parsed, args.mode, op, "do")
2794                     print_req_type(ri)           2798                     print_req_type(ri)
2795                     print_req_type_helpers(ri    2799                     print_req_type_helpers(ri)
2796                     cw.nl()                      2800                     cw.nl()
2797                     print_rsp_type(ri)           2801                     print_rsp_type(ri)
2798                     print_rsp_type_helpers(ri    2802                     print_rsp_type_helpers(ri)
2799                     cw.nl()                      2803                     cw.nl()
2800                     print_req_prototype(ri)      2804                     print_req_prototype(ri)
2801                     cw.nl()                      2805                     cw.nl()
2802                                                  2806 
2803                 if 'dump' in op:                 2807                 if 'dump' in op:
2804                     cw.p(f"/* {op.enum_name}     2808                     cw.p(f"/* {op.enum_name} - dump */")
2805                     ri = RenderInfo(cw, parse    2809                     ri = RenderInfo(cw, parsed, args.mode, op, 'dump')
2806                     print_req_type(ri)           2810                     print_req_type(ri)
2807                     print_req_type_helpers(ri    2811                     print_req_type_helpers(ri)
2808                     if not ri.type_consistent    2812                     if not ri.type_consistent:
2809                         print_rsp_type(ri)       2813                         print_rsp_type(ri)
2810                     print_wrapped_type(ri)       2814                     print_wrapped_type(ri)
2811                     print_dump_prototype(ri)     2815                     print_dump_prototype(ri)
2812                     cw.nl()                      2816                     cw.nl()
2813                                                  2817 
2814                 if op.has_ntf:                   2818                 if op.has_ntf:
2815                     cw.p(f"/* {op.enum_name}     2819                     cw.p(f"/* {op.enum_name} - notify */")
2816                     ri = RenderInfo(cw, parse    2820                     ri = RenderInfo(cw, parsed, args.mode, op, 'notify')
2817                     if not ri.type_consistent    2821                     if not ri.type_consistent:
2818                         raise Exception(f'Onl    2822                         raise Exception(f'Only notifications with consistent types supported ({op.name})')
2819                     print_wrapped_type(ri)       2823                     print_wrapped_type(ri)
2820                                                  2824 
2821             for op_name, op in parsed.ntfs.it    2825             for op_name, op in parsed.ntfs.items():
2822                 if 'event' in op:                2826                 if 'event' in op:
2823                     ri = RenderInfo(cw, parse    2827                     ri = RenderInfo(cw, parsed, args.mode, op, 'event')
2824                     cw.p(f"/* {op.enum_name}     2828                     cw.p(f"/* {op.enum_name} - event */")
2825                     print_rsp_type(ri)           2829                     print_rsp_type(ri)
2826                     cw.nl()                      2830                     cw.nl()
2827                     print_wrapped_type(ri)       2831                     print_wrapped_type(ri)
2828             cw.nl()                              2832             cw.nl()
2829         else:                                    2833         else:
2830             cw.p('/* Enums */')                  2834             cw.p('/* Enums */')
2831             put_op_name(parsed, cw)              2835             put_op_name(parsed, cw)
2832                                                  2836 
2833             for name, const in parsed.consts.    2837             for name, const in parsed.consts.items():
2834                 if isinstance(const, EnumSet)    2838                 if isinstance(const, EnumSet):
2835                     put_enum_to_str(parsed, c    2839                     put_enum_to_str(parsed, cw, const)
2836             cw.nl()                              2840             cw.nl()
2837                                                  2841 
2838             has_recursive_nests = False          2842             has_recursive_nests = False
2839             cw.p('/* Policies */')               2843             cw.p('/* Policies */')
2840             for struct in parsed.pure_nested_    2844             for struct in parsed.pure_nested_structs.values():
2841                 if struct.recursive:             2845                 if struct.recursive:
2842                     put_typol_fwd(cw, struct)    2846                     put_typol_fwd(cw, struct)
2843                     has_recursive_nests = Tru    2847                     has_recursive_nests = True
2844             if has_recursive_nests:              2848             if has_recursive_nests:
2845                 cw.nl()                          2849                 cw.nl()
2846             for name in parsed.pure_nested_st    2850             for name in parsed.pure_nested_structs:
2847                 struct = Struct(parsed, name)    2851                 struct = Struct(parsed, name)
2848                 put_typol(cw, struct)            2852                 put_typol(cw, struct)
2849             for name in parsed.root_sets:        2853             for name in parsed.root_sets:
2850                 struct = Struct(parsed, name)    2854                 struct = Struct(parsed, name)
2851                 put_typol(cw, struct)            2855                 put_typol(cw, struct)
2852                                                  2856 
2853             cw.p('/* Common nested types */')    2857             cw.p('/* Common nested types */')
2854             if has_recursive_nests:              2858             if has_recursive_nests:
2855                 for attr_set, struct in parse    2859                 for attr_set, struct in parsed.pure_nested_structs.items():
2856                     ri = RenderInfo(cw, parse    2860                     ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set)
2857                     free_rsp_nested_prototype    2861                     free_rsp_nested_prototype(ri)
2858                     if struct.request:           2862                     if struct.request:
2859                         put_req_nested_protot    2863                         put_req_nested_prototype(ri, struct)
2860                     if struct.reply:             2864                     if struct.reply:
2861                         parse_rsp_nested_prot    2865                         parse_rsp_nested_prototype(ri, struct)
2862                 cw.nl()                          2866                 cw.nl()
2863             for attr_set, struct in parsed.pu    2867             for attr_set, struct in parsed.pure_nested_structs.items():
2864                 ri = RenderInfo(cw, parsed, a    2868                 ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set)
2865                                                  2869 
2866                 free_rsp_nested(ri, struct)      2870                 free_rsp_nested(ri, struct)
2867                 if struct.request:               2871                 if struct.request:
2868                     put_req_nested(ri, struct    2872                     put_req_nested(ri, struct)
2869                 if struct.reply:                 2873                 if struct.reply:
2870                     parse_rsp_nested(ri, stru    2874                     parse_rsp_nested(ri, struct)
2871                                                  2875 
2872             for op_name, op in parsed.ops.ite    2876             for op_name, op in parsed.ops.items():
2873                 cw.p(f"/* ============== {op.    2877                 cw.p(f"/* ============== {op.enum_name} ============== */")
2874                 if 'do' in op and 'event' not    2878                 if 'do' in op and 'event' not in op:
2875                     cw.p(f"/* {op.enum_name}     2879                     cw.p(f"/* {op.enum_name} - do */")
2876                     ri = RenderInfo(cw, parse    2880                     ri = RenderInfo(cw, parsed, args.mode, op, "do")
2877                     print_req_free(ri)           2881                     print_req_free(ri)
2878                     print_rsp_free(ri)           2882                     print_rsp_free(ri)
2879                     parse_rsp_msg(ri)            2883                     parse_rsp_msg(ri)
2880                     print_req(ri)                2884                     print_req(ri)
2881                     cw.nl()                      2885                     cw.nl()
2882                                                  2886 
2883                 if 'dump' in op:                 2887                 if 'dump' in op:
2884                     cw.p(f"/* {op.enum_name}     2888                     cw.p(f"/* {op.enum_name} - dump */")
2885                     ri = RenderInfo(cw, parse    2889                     ri = RenderInfo(cw, parsed, args.mode, op, "dump")
2886                     if not ri.type_consistent    2890                     if not ri.type_consistent:
2887                         parse_rsp_msg(ri, der    2891                         parse_rsp_msg(ri, deref=True)
2888                     print_req_free(ri)           2892                     print_req_free(ri)
2889                     print_dump_type_free(ri)     2893                     print_dump_type_free(ri)
2890                     print_dump(ri)               2894                     print_dump(ri)
2891                     cw.nl()                      2895                     cw.nl()
2892                                                  2896 
2893                 if op.has_ntf:                   2897                 if op.has_ntf:
2894                     cw.p(f"/* {op.enum_name}     2898                     cw.p(f"/* {op.enum_name} - notify */")
2895                     ri = RenderInfo(cw, parse    2899                     ri = RenderInfo(cw, parsed, args.mode, op, 'notify')
2896                     if not ri.type_consistent    2900                     if not ri.type_consistent:
2897                         raise Exception(f'Onl    2901                         raise Exception(f'Only notifications with consistent types supported ({op.name})')
2898                     print_ntf_type_free(ri)      2902                     print_ntf_type_free(ri)
2899                                                  2903 
2900             for op_name, op in parsed.ntfs.it    2904             for op_name, op in parsed.ntfs.items():
2901                 if 'event' in op:                2905                 if 'event' in op:
2902                     cw.p(f"/* {op.enum_name}     2906                     cw.p(f"/* {op.enum_name} - event */")
2903                                                  2907 
2904                     ri = RenderInfo(cw, parse    2908                     ri = RenderInfo(cw, parsed, args.mode, op, "do")
2905                     parse_rsp_msg(ri)            2909                     parse_rsp_msg(ri)
2906                                                  2910 
2907                     ri = RenderInfo(cw, parse    2911                     ri = RenderInfo(cw, parsed, args.mode, op, "event")
2908                     print_ntf_type_free(ri)      2912                     print_ntf_type_free(ri)
2909             cw.nl()                              2913             cw.nl()
2910             render_user_family(parsed, cw, Fa    2914             render_user_family(parsed, cw, False)
2911                                                  2915 
2912     if args.header:                              2916     if args.header:
2913         cw.p(f'#endif /* {hdr_prot} */')         2917         cw.p(f'#endif /* {hdr_prot} */')
2914                                                  2918 
2915                                                  2919 
2916 if __name__ == "__main__":                       2920 if __name__ == "__main__":
2917     main()                                       2921     main()
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php