~ [ 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-5.14.21)


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