2023-01-30 18:33:54 -08:00
#!/usr/bin/env python3
2023-03-15 16:03:50 -07:00
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
2023-01-20 09:50:36 -08:00
import argparse
2023-01-25 16:02:35 -08:00
import collections
2023-10-27 15:34:08 -07:00
import filecmp
2023-01-20 09:50:36 -08:00
import os
2023-06-09 14:43:35 -07:00
import re
2023-08-18 13:19:27 +02:00
import shutil
import tempfile
2023-01-20 09:50:36 -08:00
import yaml
2023-03-07 16:39:22 -08:00
from lib import SpecFamily , SpecAttrSet , SpecAttr , SpecOperation , SpecEnumSet , SpecEnumEntry
2023-01-30 18:33:44 -08:00
2023-01-20 09:50:36 -08:00
def c_upper ( name ) :
return name . upper ( ) . replace ( ' - ' , ' _ ' )
def c_lower ( name ) :
return name . lower ( ) . replace ( ' - ' , ' _ ' )
2023-10-18 09:39:17 -07:00
def limit_to_number ( name ) :
"""
Turn a string limit like u32 - max or s64 - min into its numerical value
"""
if name [ 0 ] == ' u ' and name . endswith ( ' -min ' ) :
return 0
width = int ( name [ 1 : - 4 ] )
if name [ 0 ] == ' s ' :
width - = 1
value = ( 1 << width ) - 1
if name [ 0 ] == ' s ' and name . endswith ( ' -min ' ) :
value = - value - 1
return value
2023-01-20 09:50:36 -08:00
class BaseNlLib :
def get_family_id ( self ) :
return ' ys->family_id '
2023-01-30 18:33:44 -08:00
class Type ( SpecAttr ) :
def __init__ ( self , family , attr_set , attr , value ) :
super ( ) . __init__ ( family , attr_set , attr , value )
2023-01-20 09:50:36 -08:00
self . attr = attr
2023-01-30 18:33:44 -08:00
self . attr_set = attr_set
2023-01-20 09:50:36 -08:00
self . type = attr [ ' type ' ]
self . checks = attr . get ( ' checks ' , { } )
2023-10-18 09:39:15 -07:00
self . request = False
self . reply = False
2023-01-20 09:50:36 -08:00
if ' len ' in attr :
self . len = attr [ ' len ' ]
2023-10-18 09:39:16 -07:00
2023-01-20 09:50:36 -08:00
if ' nested-attributes ' in attr :
self . nested_attrs = attr [ ' nested-attributes ' ]
if self . nested_attrs == family . name :
2023-11-22 19:08:44 -08:00
self . nested_render_name = c_lower ( f " { family . name } " )
2023-01-20 09:50:36 -08:00
else :
2023-11-22 19:08:44 -08:00
self . nested_render_name = c_lower ( f " { family . name } _ { self . nested_attrs } " )
2023-01-20 09:50:36 -08:00
2023-06-09 14:43:40 -07:00
if self . nested_attrs in self . family . consts :
self . nested_struct_type = ' struct ' + self . nested_render_name + ' _ '
else :
self . nested_struct_type = ' struct ' + self . nested_render_name
2023-01-20 09:50:36 -08:00
self . c_name = c_lower ( self . name )
if self . c_name in _C_KW :
self . c_name + = ' _ '
2023-01-30 18:33:44 -08:00
# Added by resolve():
self . enum_name = None
delattr ( self , " enum_name " )
2023-01-20 09:50:36 -08:00
2023-10-18 09:39:17 -07:00
def get_limit ( self , limit , default = None ) :
value = self . checks . get ( limit , default )
if value is None :
return value
if not isinstance ( value , int ) :
value = limit_to_number ( value )
return value
2023-01-30 18:33:44 -08:00
def resolve ( self ) :
2023-06-09 14:43:37 -07:00
if ' name-prefix ' in self . attr :
enum_name = f " { self . attr [ ' name-prefix ' ] } { self . name } "
else :
enum_name = f " { self . attr_set . name_prefix } { self . name } "
self . enum_name = c_upper ( enum_name )
2023-01-20 09:50:36 -08:00
def is_multi_val ( self ) :
return None
def is_scalar ( self ) :
return self . type in { ' u8 ' , ' u16 ' , ' u32 ' , ' u64 ' , ' s32 ' , ' s64 ' }
2023-12-13 15:14:29 -08:00
def is_recursive ( self ) :
return False
2023-12-13 15:14:31 -08:00
def is_recursive_for_op ( self , ri ) :
return self . is_recursive ( ) and not ri . op
2023-01-20 09:50:36 -08:00
def presence_type ( self ) :
return ' bit '
def presence_member ( self , space , type_filter ) :
if self . presence_type ( ) != type_filter :
return
if self . presence_type ( ) == ' bit ' :
pfx = ' __ ' if space == ' user ' else ' '
return f " { pfx } u32 { self . c_name } :1; "
if self . presence_type ( ) == ' len ' :
pfx = ' __ ' if space == ' user ' else ' '
return f " { pfx } u32 { self . c_name } _len; "
def _complex_member_type ( self , ri ) :
return None
def free_needs_iter ( self ) :
return False
def free ( self , ri , var , ref ) :
if self . is_multi_val ( ) or self . presence_type ( ) == ' len ' :
ri . cw . p ( f ' free( { var } -> { ref } { self . c_name } ); ' )
def arg_member ( self , ri ) :
member = self . _complex_member_type ( ri )
if member :
2023-06-06 12:43:00 -07:00
arg = [ member + ' * ' + self . c_name ]
if self . presence_type ( ) == ' count ' :
arg + = [ ' unsigned int n_ ' + self . c_name ]
return arg
2023-01-20 09:50:36 -08:00
raise Exception ( f " Struct member not implemented for class type { self . type } " )
def struct_member ( self , ri ) :
if self . is_multi_val ( ) :
ri . cw . p ( f " unsigned int n_ { self . c_name } ; " )
member = self . _complex_member_type ( ri )
if member :
ptr = ' * ' if self . is_multi_val ( ) else ' '
2023-12-13 15:14:31 -08:00
if self . is_recursive_for_op ( ri ) :
ptr = ' * '
2023-01-20 09:50:36 -08:00
ri . cw . p ( f " { member } { ptr } { self . c_name } ; " )
return
members = self . arg_member ( ri )
for one in members :
ri . cw . p ( one + ' ; ' )
def _attr_policy ( self , policy ) :
return ' { .type = ' + policy + ' , } '
def attr_policy ( self , cw ) :
policy = c_upper ( ' nla- ' + self . attr [ ' type ' ] )
spec = self . _attr_policy ( policy )
cw . p ( f " \t [ { self . enum_name } ] = { spec } , " )
def _attr_typol ( self ) :
raise Exception ( f " Type policy not implemented for class type { self . type } " )
def attr_typol ( self , cw ) :
typol = self . _attr_typol ( )
cw . p ( f ' [ { self . enum_name } ] = { " { " } .name = " { self . name } " , { typol } { " } " } , ' )
def _attr_put_line ( self , ri , var , line ) :
if self . presence_type ( ) == ' bit ' :
ri . cw . p ( f " if ( { var } ->_present. { self . c_name } ) " )
elif self . presence_type ( ) == ' len ' :
ri . cw . p ( f " if ( { var } ->_present. { self . c_name } _len) " )
ri . cw . p ( f " { line } ; " )
def _attr_put_simple ( self , ri , var , put_type ) :
2024-02-27 14:30:19 -08:00
line = f " ynl_attr_put_ { put_type } (nlh, { self . enum_name } , { var } -> { self . c_name } ) "
2023-01-20 09:50:36 -08:00
self . _attr_put_line ( ri , var , line )
def attr_put ( self , ri , var ) :
raise Exception ( f " Put not implemented for class type { self . type } " )
def _attr_get ( self , ri , var ) :
raise Exception ( f " Attr get not implemented for class type { self . type } " )
def attr_get ( self , ri , var , first ) :
lines , init_lines , local_vars = self . _attr_get ( ri , var )
if type ( lines ) is str :
lines = [ lines ]
if type ( init_lines ) is str :
init_lines = [ init_lines ]
kw = ' if ' if first else ' else if '
2023-06-08 14:11:53 -07:00
ri . cw . block_start ( line = f " { kw } (type == { self . enum_name } ) " )
2023-01-20 09:50:36 -08:00
if local_vars :
for local in local_vars :
ri . cw . p ( local )
ri . cw . nl ( )
if not self . is_multi_val ( ) :
ri . cw . p ( " if (ynl_attr_validate(yarg, attr)) " )
2024-02-27 14:30:29 -08:00
ri . cw . p ( " return YNL_PARSE_CB_ERROR; " )
2023-01-20 09:50:36 -08:00
if self . presence_type ( ) == ' bit ' :
ri . cw . p ( f " { var } ->_present. { self . c_name } = 1; " )
if init_lines :
ri . cw . nl ( )
for line in init_lines :
ri . cw . p ( line )
for line in lines :
ri . cw . p ( line )
ri . cw . block_end ( )
2023-06-01 19:35:40 -07:00
return True
2023-01-20 09:50:36 -08:00
def _setter_lines ( self , ri , member , presence ) :
raise Exception ( f " Setter not implemented for class type { self . type } " )
def setter ( self , ri , space , direction , deref = False , ref = None ) :
ref = ( ref if ref else [ ] ) + [ self . c_name ]
var = " req "
member = f " { var } -> { ' . ' . join ( ref ) } "
code = [ ]
presence = ' '
for i in range ( 0 , len ( ref ) ) :
presence = f " { var } -> { ' . ' . join ( ref [ : i ] + [ ' ' ] ) } _present. { ref [ i ] } "
if self . presence_type ( ) == ' bit ' :
code . append ( presence + ' = 1; ' )
code + = self . _setter_lines ( ri , member , presence )
2023-06-06 12:43:00 -07:00
func_name = f " { op_prefix ( ri , direction , deref = deref ) } _set_ { ' _ ' . join ( ref ) } "
free = bool ( [ x for x in code if ' free( ' in x ] )
alloc = bool ( [ x for x in code if ' alloc( ' in x ] )
if free and not alloc :
func_name = ' __ ' + func_name
ri . cw . write_func ( ' static inline void ' , func_name , body = code ,
2023-01-20 09:50:36 -08:00
args = [ f ' { type_name ( ri , direction , deref = deref ) } * { var } ' ] + self . arg_member ( ri ) )
class TypeUnused ( Type ) :
def presence_type ( self ) :
return ' '
2023-06-01 19:35:40 -07:00
def arg_member ( self , ri ) :
return [ ]
def _attr_get ( self , ri , var ) :
2024-02-27 14:30:29 -08:00
return [ ' return YNL_PARSE_CB_ERROR; ' ] , None , None
2023-06-01 19:35:40 -07:00
2023-01-20 09:50:36 -08:00
def _attr_typol ( self ) :
return ' .type = YNL_PT_REJECT, '
def attr_policy ( self , cw ) :
pass
2023-12-13 15:14:28 -08:00
def attr_put ( self , ri , var ) :
pass
def attr_get ( self , ri , var , first ) :
pass
def setter ( self , ri , space , direction , deref = False , ref = None ) :
pass
2023-01-20 09:50:36 -08:00
class TypePad ( Type ) :
def presence_type ( self ) :
return ' '
2023-06-01 19:35:40 -07:00
def arg_member ( self , ri ) :
return [ ]
2023-01-20 09:50:36 -08:00
def _attr_typol ( self ) :
2023-06-01 19:35:40 -07:00
return ' .type = YNL_PT_IGNORE, '
2023-06-08 14:12:00 -07:00
def attr_put ( self , ri , var ) :
pass
2023-06-01 19:35:40 -07:00
def attr_get ( self , ri , var , first ) :
pass
2023-01-20 09:50:36 -08:00
def attr_policy ( self , cw ) :
pass
2023-06-08 14:12:00 -07:00
def setter ( self , ri , space , direction , deref = False , ref = None ) :
pass
2023-01-20 09:50:36 -08:00
class TypeScalar ( Type ) :
2023-01-30 18:33:44 -08:00
def __init__ ( self , family , attr_set , attr , value ) :
super ( ) . __init__ ( family , attr_set , attr , value )
self . byte_order_comment = ' '
if ' byte-order ' in attr :
self . byte_order_comment = f " /* { attr [ ' byte-order ' ] } */ "
2023-10-18 09:39:16 -07:00
if ' enum ' in self . attr :
enum = self . family . consts [ self . attr [ ' enum ' ] ]
low , high = enum . value_range ( )
if ' min ' not in self . checks :
if low != 0 or self . type [ 0 ] == ' s ' :
self . checks [ ' min ' ] = low
if ' max ' not in self . checks :
self . checks [ ' max ' ] = high
if ' min ' in self . checks and ' max ' in self . checks :
2023-10-18 09:39:17 -07:00
if self . get_limit ( ' min ' ) > self . get_limit ( ' max ' ) :
raise Exception ( f ' Invalid limit for " { self . name } " min: { self . get_limit ( " min " ) } max: { self . get_limit ( " max " ) } ' )
2023-10-18 09:39:16 -07:00
self . checks [ ' range ' ] = True
2023-10-18 09:39:17 -07:00
low = min ( self . get_limit ( ' min ' , 0 ) , self . get_limit ( ' max ' , 0 ) )
high = max ( self . get_limit ( ' min ' , 0 ) , self . get_limit ( ' max ' , 0 ) )
2023-10-18 09:39:16 -07:00
if low < 0 and self . type [ 0 ] == ' u ' :
raise Exception ( f ' Invalid limit for " { self . name } " negative limit for unsigned type ' )
if low < - 32768 or high > 32767 :
self . checks [ ' full-range ' ] = True
2023-01-30 18:33:44 -08:00
# Added by resolve():
self . is_bitfield = None
delattr ( self , " is_bitfield " )
self . type_name = None
delattr ( self , " type_name " )
def resolve ( self ) :
self . resolve_up ( super ( ) )
2023-01-20 09:50:36 -08:00
if ' enum-as-flags ' in self . attr and self . attr [ ' enum-as-flags ' ] :
self . is_bitfield = True
2023-01-30 18:33:44 -08:00
elif ' enum ' in self . attr :
self . is_bitfield = self . family . consts [ self . attr [ ' enum ' ] ] [ ' type ' ] == ' flags '
else :
self . is_bitfield = False
2023-01-20 09:50:36 -08:00
2023-12-13 15:14:26 -08:00
if not self . is_bitfield and ' enum ' in self . attr :
self . type_name = self . family . consts [ self . attr [ ' enum ' ] ] . user_type
2023-10-18 14:39:21 -07:00
elif self . is_auto_scalar :
self . type_name = ' __ ' + self . type [ 0 ] + ' 64 '
2023-01-20 09:50:36 -08:00
else :
self . type_name = ' __ ' + self . type
def _attr_policy ( self , policy ) :
if ' flags-mask ' in self . checks or self . is_bitfield :
if self . is_bitfield :
2023-03-24 12:03:56 -07:00
enum = self . family . consts [ self . attr [ ' enum ' ] ]
mask = enum . get_mask ( as_flags = True )
2023-01-20 09:50:36 -08:00
else :
flags = self . family . consts [ self . checks [ ' flags-mask ' ] ]
flag_cnt = len ( flags [ ' entries ' ] )
mask = ( 1 << flag_cnt ) - 1
return f " NLA_POLICY_MASK( { policy } , 0x { mask : x } ) "
2023-10-18 09:39:16 -07:00
elif ' full-range ' in self . checks :
return f " NLA_POLICY_FULL_RANGE( { policy } , & { c_lower ( self . enum_name ) } _range) "
elif ' range ' in self . checks :
2023-10-18 09:39:17 -07:00
return f " NLA_POLICY_RANGE( { policy } , { self . get_limit ( ' min ' ) } , { self . get_limit ( ' max ' ) } ) "
2023-01-20 09:50:36 -08:00
elif ' min ' in self . checks :
2023-10-18 09:39:17 -07:00
return f " NLA_POLICY_MIN( { policy } , { self . get_limit ( ' min ' ) } ) "
2023-10-18 09:39:16 -07:00
elif ' max ' in self . checks :
2023-10-18 09:39:17 -07:00
return f " NLA_POLICY_MAX( { policy } , { self . get_limit ( ' max ' ) } ) "
2023-01-20 09:50:36 -08:00
return super ( ) . _attr_policy ( policy )
def _attr_typol ( self ) :
2023-10-18 14:39:21 -07:00
return f ' .type = YNL_PT_U { c_upper ( self . type [ 1 : ] ) } , '
2023-01-20 09:50:36 -08:00
def arg_member ( self , ri ) :
return [ f ' { self . type_name } { self . c_name } { self . byte_order_comment } ' ]
def attr_put ( self , ri , var ) :
2024-02-27 14:30:19 -08:00
self . _attr_put_simple ( ri , var , self . type )
2023-01-20 09:50:36 -08:00
def _attr_get ( self , ri , var ) :
2024-02-27 14:30:19 -08:00
return f " { var } -> { self . c_name } = ynl_attr_get_ { self . type } (attr); " , None , None
2023-01-20 09:50:36 -08:00
def _setter_lines ( self , ri , member , presence ) :
return [ f " { member } = { self . c_name } ; " ]
class TypeFlag ( Type ) :
def arg_member ( self , ri ) :
return [ ]
def _attr_typol ( self ) :
return ' .type = YNL_PT_FLAG, '
def attr_put ( self , ri , var ) :
2024-02-27 14:30:19 -08:00
self . _attr_put_line ( ri , var , f " ynl_attr_put(nlh, { self . enum_name } , NULL, 0) " )
2023-01-20 09:50:36 -08:00
def _attr_get ( self , ri , var ) :
return [ ] , None , None
def _setter_lines ( self , ri , member , presence ) :
return [ ]
class TypeString ( Type ) :
def arg_member ( self , ri ) :
return [ f " const char * { self . c_name } " ]
def presence_type ( self ) :
return ' len '
def struct_member ( self , ri ) :
ri . cw . p ( f " char * { self . c_name } ; " )
def _attr_typol ( self ) :
return f ' .type = YNL_PT_NUL_STR, '
def _attr_policy ( self , policy ) :
2023-10-23 11:17:06 -07:00
if ' exact-len ' in self . checks :
mem = ' NLA_POLICY_EXACT_LEN( ' + str ( self . checks [ ' exact-len ' ] ) + ' ) '
else :
mem = ' { .type = ' + policy
if ' max-len ' in self . checks :
mem + = ' , .len = ' + str ( self . get_limit ( ' max-len ' ) )
mem + = ' , } '
2023-01-20 09:50:36 -08:00
return mem
def attr_policy ( self , cw ) :
if self . checks . get ( ' unterminated-ok ' , False ) :
policy = ' NLA_STRING '
else :
policy = ' NLA_NUL_STRING '
spec = self . _attr_policy ( policy )
cw . p ( f " \t [ { self . enum_name } ] = { spec } , " )
def attr_put ( self , ri , var ) :
2024-02-27 14:30:19 -08:00
self . _attr_put_simple ( ri , var , ' str ' )
2023-01-20 09:50:36 -08:00
def _attr_get ( self , ri , var ) :
len_mem = var + ' ->_present. ' + self . c_name + ' _len '
return [ f " { len_mem } = len; " ,
f " { var } -> { self . c_name } = malloc(len + 1); " ,
2024-02-27 14:30:19 -08:00
f " memcpy( { var } -> { self . c_name } , ynl_attr_get_str(attr), len); " ,
2023-01-20 09:50:36 -08:00
f " { var } -> { self . c_name } [len] = 0; " ] , \
2024-02-27 14:30:19 -08:00
[ ' len = strnlen(ynl_attr_get_str(attr), ynl_attr_data_len(attr)); ' ] , \
2023-01-20 09:50:36 -08:00
[ ' unsigned int len; ' ]
def _setter_lines ( self , ri , member , presence ) :
return [ f " free( { member } ); " ,
f " { presence } _len = strlen( { self . c_name } ); " ,
f " { member } = malloc( { presence } _len + 1); " ,
f ' memcpy( { member } , { self . c_name } , { presence } _len); ' ,
f ' { member } [ { presence } _len] = 0; ' ]
class TypeBinary ( Type ) :
def arg_member ( self , ri ) :
return [ f " const void * { self . c_name } " , ' size_t len ' ]
def presence_type ( self ) :
return ' len '
def struct_member ( self , ri ) :
ri . cw . p ( f " void * { self . c_name } ; " )
def _attr_typol ( self ) :
return f ' .type = YNL_PT_BINARY, '
def _attr_policy ( self , policy ) :
2023-10-23 11:17:06 -07:00
if ' exact-len ' in self . checks :
mem = ' NLA_POLICY_EXACT_LEN( ' + str ( self . checks [ ' exact-len ' ] ) + ' ) '
2023-01-20 09:50:36 -08:00
else :
2023-10-23 11:17:06 -07:00
mem = ' { '
if len ( self . checks ) == 1 and ' min-len ' in self . checks :
mem + = ' .len = ' + str ( self . get_limit ( ' min-len ' ) )
elif len ( self . checks ) == 0 :
mem + = ' .type = NLA_BINARY '
else :
raise Exception ( ' One or more of binary type checks not implemented, yet ' )
mem + = ' , } '
2023-01-20 09:50:36 -08:00
return mem
def attr_put ( self , ri , var ) :
2024-02-27 14:30:19 -08:00
self . _attr_put_line ( ri , var , f " ynl_attr_put(nlh, { self . enum_name } , " +
f " { var } -> { self . c_name } , { var } ->_present. { self . c_name } _len) " )
2023-01-20 09:50:36 -08:00
def _attr_get ( self , ri , var ) :
len_mem = var + ' ->_present. ' + self . c_name + ' _len '
return [ f " { len_mem } = len; " ,
f " { var } -> { self . c_name } = malloc(len); " ,
2024-02-27 14:30:19 -08:00
f " memcpy( { var } -> { self . c_name } , ynl_attr_data(attr), len); " ] , \
[ ' len = ynl_attr_data_len(attr); ' ] , \
2023-01-20 09:50:36 -08:00
[ ' unsigned int len; ' ]
def _setter_lines ( self , ri , member , presence ) :
return [ f " free( { member } ); " ,
2023-08-23 17:30:53 -07:00
f " { presence } _len = len; " ,
2023-01-20 09:50:36 -08:00
f " { member } = malloc( { presence } _len); " ,
f ' memcpy( { member } , { self . c_name } , { presence } _len); ' ]
2023-10-21 13:27:03 +02:00
class TypeBitfield32 ( Type ) :
def _complex_member_type ( self , ri ) :
return " struct nla_bitfield32 "
def _attr_typol ( self ) :
return f ' .type = YNL_PT_BITFIELD32, '
def _attr_policy ( self , policy ) :
if not ' enum ' in self . attr :
raise Exception ( ' Enum required for bitfield32 attr ' )
enum = self . family . consts [ self . attr [ ' enum ' ] ]
mask = enum . get_mask ( as_flags = True )
return f " NLA_POLICY_BITFIELD32( { mask } ) "
def attr_put ( self , ri , var ) :
2024-02-27 14:30:19 -08:00
line = f " ynl_attr_put(nlh, { self . enum_name } , & { var } -> { self . c_name } , sizeof(struct nla_bitfield32)) "
2023-10-21 13:27:03 +02:00
self . _attr_put_line ( ri , var , line )
def _attr_get ( self , ri , var ) :
2024-02-27 14:30:19 -08:00
return f " memcpy(& { var } -> { self . c_name } , ynl_attr_data(attr), sizeof(struct nla_bitfield32)); " , None , None
2023-10-21 13:27:03 +02:00
def _setter_lines ( self , ri , member , presence ) :
return [ f " memcpy(& { member } , { self . c_name } , sizeof(struct nla_bitfield32)); " ]
2023-01-20 09:50:36 -08:00
class TypeNest ( Type ) :
2023-12-13 15:14:29 -08:00
def is_recursive ( self ) :
return self . family . pure_nested_structs [ self . nested_attrs ] . recursive
2023-01-20 09:50:36 -08:00
def _complex_member_type ( self , ri ) :
2023-06-09 14:43:40 -07:00
return self . nested_struct_type
2023-01-20 09:50:36 -08:00
def free ( self , ri , var , ref ) :
2023-12-13 15:14:31 -08:00
at = ' & '
if self . is_recursive_for_op ( ri ) :
at = ' '
ri . cw . p ( f ' if ( { var } -> { ref } { self . c_name } ) ' )
ri . cw . p ( f ' { self . nested_render_name } _free( { at } { var } -> { ref } { self . c_name } ); ' )
2023-01-20 09:50:36 -08:00
def _attr_typol ( self ) :
return f ' .type = YNL_PT_NEST, .nest = & { self . nested_render_name } _nest, '
def _attr_policy ( self , policy ) :
return ' NLA_POLICY_NESTED( ' + self . nested_render_name + ' _nl_policy) '
def attr_put ( self , ri , var ) :
2023-12-13 15:14:31 -08:00
at = ' ' if self . is_recursive_for_op ( ri ) else ' & '
2023-01-20 09:50:36 -08:00
self . _attr_put_line ( ri , var , f " { self . nested_render_name } _put(nlh, " +
2023-12-13 15:14:31 -08:00
f " { self . enum_name } , { at } { var } -> { self . c_name } ) " )
2023-01-20 09:50:36 -08:00
def _attr_get ( self , ri , var ) :
2023-06-01 19:35:43 -07:00
get_lines = [ f " if ( { self . nested_render_name } _parse(&parg, attr)) " ,
2024-02-27 14:30:29 -08:00
" return YNL_PARSE_CB_ERROR; " ]
2023-01-20 09:50:36 -08:00
init_lines = [ f " parg.rsp_policy = & { self . nested_render_name } _nest; " ,
f " parg.data = & { var } -> { self . c_name } ; " ]
return get_lines , init_lines , None
def setter ( self , ri , space , direction , deref = False , ref = None ) :
ref = ( ref if ref else [ ] ) + [ self . c_name ]
for _ , attr in ri . family . pure_nested_structs [ self . nested_attrs ] . member_list ( ) :
2023-12-13 15:14:31 -08:00
if attr . is_recursive ( ) :
continue
2023-01-20 09:50:36 -08:00
attr . setter ( ri , self . nested_attrs , direction , deref = deref , ref = ref )
class TypeMultiAttr ( Type ) :
2023-06-12 08:59:20 -07:00
def __init__ ( self , family , attr_set , attr , value , base_type ) :
super ( ) . __init__ ( family , attr_set , attr , value )
self . base_type = base_type
2023-01-20 09:50:36 -08:00
def is_multi_val ( self ) :
return True
def presence_type ( self ) :
return ' count '
def _complex_member_type ( self , ri ) :
if ' type ' not in self . attr or self . attr [ ' type ' ] == ' nest ' :
2023-06-09 14:43:40 -07:00
return self . nested_struct_type
2023-01-20 09:50:36 -08:00
elif self . attr [ ' type ' ] in scalars :
scalar_pfx = ' __ ' if ri . ku_space == ' user ' else ' '
return scalar_pfx + self . attr [ ' type ' ]
else :
raise Exception ( f " Sub-type { self . attr [ ' type ' ] } not supported yet " )
def free_needs_iter ( self ) :
return ' type ' not in self . attr or self . attr [ ' type ' ] == ' nest '
def free ( self , ri , var , ref ) :
2023-06-06 12:43:00 -07:00
if self . attr [ ' type ' ] in scalars :
ri . cw . p ( f " free( { var } -> { ref } { self . c_name } ); " )
elif ' type ' not in self . attr or self . attr [ ' type ' ] == ' nest ' :
2023-01-20 09:50:36 -08:00
ri . cw . p ( f " for (i = 0; i < { var } -> { ref } n_ { self . c_name } ; i++) " )
ri . cw . p ( f ' { self . nested_render_name } _free(& { var } -> { ref } { self . c_name } [i]); ' )
2023-06-06 12:43:00 -07:00
ri . cw . p ( f " free( { var } -> { ref } { self . c_name } ); " )
else :
raise Exception ( f " Free of MultiAttr sub-type { self . attr [ ' type ' ] } not supported yet " )
2023-01-20 09:50:36 -08:00
2023-06-12 08:59:20 -07:00
def _attr_policy ( self , policy ) :
return self . base_type . _attr_policy ( policy )
2023-01-20 09:50:36 -08:00
def _attr_typol ( self ) :
2023-06-12 08:59:20 -07:00
return self . base_type . _attr_typol ( )
2023-01-20 09:50:36 -08:00
def _attr_get ( self , ri , var ) :
2023-06-06 12:43:01 -07:00
return f ' n_ { self . c_name } ++; ' , None , None
2023-01-20 09:50:36 -08:00
2023-06-06 12:43:00 -07:00
def attr_put ( self , ri , var ) :
if self . attr [ ' type ' ] in scalars :
2024-02-27 14:30:19 -08:00
put_type = self . type
2023-06-06 12:43:00 -07:00
ri . cw . p ( f " for (unsigned int i = 0; i < { var } ->n_ { self . c_name } ; i++) " )
2024-02-27 14:30:19 -08:00
ri . cw . p ( f " ynl_attr_put_ { put_type } (nlh, { self . enum_name } , { var } -> { self . c_name } [i]); " )
2023-06-06 12:43:00 -07:00
elif ' type ' not in self . attr or self . attr [ ' type ' ] == ' nest ' :
ri . cw . p ( f " for (unsigned int i = 0; i < { var } ->n_ { self . c_name } ; i++) " )
self . _attr_put_line ( ri , var , f " { self . nested_render_name } _put(nlh, " +
f " { self . enum_name } , & { var } -> { self . c_name } [i]) " )
else :
raise Exception ( f " Put of MultiAttr sub-type { self . attr [ ' type ' ] } not supported yet " )
def _setter_lines ( self , ri , member , presence ) :
# For multi-attr we have a count, not presence, hack up the presence
presence = presence [ : - ( len ( ' _present. ' ) + len ( self . c_name ) ) ] + " n_ " + self . c_name
return [ f " free( { member } ); " ,
f " { member } = { self . c_name } ; " ,
f " { presence } = n_ { self . c_name } ; " ]
2023-01-20 09:50:36 -08:00
class TypeArrayNest ( Type ) :
def is_multi_val ( self ) :
return True
def presence_type ( self ) :
return ' count '
def _complex_member_type ( self , ri ) :
if ' sub-type ' not in self . attr or self . attr [ ' sub-type ' ] == ' nest ' :
2023-06-09 14:43:40 -07:00
return self . nested_struct_type
2023-01-20 09:50:36 -08:00
elif self . attr [ ' sub-type ' ] in scalars :
scalar_pfx = ' __ ' if ri . ku_space == ' user ' else ' '
return scalar_pfx + self . attr [ ' sub-type ' ]
else :
raise Exception ( f " Sub-type { self . attr [ ' sub-type ' ] } not supported yet " )
def _attr_typol ( self ) :
return f ' .type = YNL_PT_NEST, .nest = & { self . nested_render_name } _nest, '
def _attr_get ( self , ri , var ) :
local_vars = [ ' const struct nlattr *attr2; ' ]
get_lines = [ f ' attr_ { self . c_name } = attr; ' ,
2024-02-27 14:30:20 -08:00
' ynl_attr_for_each_nested(attr2, attr) ' ,
2023-01-20 09:50:36 -08:00
f ' \t { var } ->n_ { self . c_name } ++; ' ]
return get_lines , None , local_vars
class TypeNestTypeValue ( Type ) :
def _complex_member_type ( self , ri ) :
2023-06-09 14:43:40 -07:00
return self . nested_struct_type
2023-01-20 09:50:36 -08:00
def _attr_typol ( self ) :
return f ' .type = YNL_PT_NEST, .nest = & { self . nested_render_name } _nest, '
def _attr_get ( self , ri , var ) :
prev = ' attr '
tv_args = ' '
get_lines = [ ]
local_vars = [ ]
init_lines = [ f " parg.rsp_policy = & { self . nested_render_name } _nest; " ,
f " parg.data = & { var } -> { self . c_name } ; " ]
if ' type-value ' in self . attr :
tv_names = [ c_lower ( x ) for x in self . attr [ " type-value " ] ]
local_vars + = [ f ' const struct nlattr *attr_ { " , *attr_ " . join ( tv_names ) } ; ' ]
local_vars + = [ f ' __u32 { " , " . join ( tv_names ) } ; ' ]
for level in self . attr [ " type-value " ] :
level = c_lower ( level )
2024-02-27 14:30:19 -08:00
get_lines + = [ f ' attr_ { level } = ynl_attr_data( { prev } ); ' ]
get_lines + = [ f ' { level } = ynl_attr_type(attr_ { level } ); ' ]
2023-01-20 09:50:36 -08:00
prev = ' attr_ ' + level
tv_args = f " , { ' , ' . join ( tv_names ) } "
get_lines + = [ f " { self . nested_render_name } _parse(&parg, { prev } { tv_args } ); " ]
return get_lines , init_lines , local_vars
class Struct :
def __init__ ( self , family , space_name , type_list = None , inherited = None ) :
self . family = family
self . space_name = space_name
self . attr_set = family . attr_sets [ space_name ]
# Use list to catch comparisons with empty sets
self . _inherited = inherited if inherited is not None else [ ]
self . inherited = [ ]
self . nested = type_list is None
if family . name == c_lower ( space_name ) :
2023-11-22 19:08:44 -08:00
self . render_name = c_lower ( family . name )
2023-01-20 09:50:36 -08:00
else :
2023-11-22 19:08:44 -08:00
self . render_name = c_lower ( family . name + ' - ' + space_name )
2023-01-20 09:50:36 -08:00
self . struct_name = ' struct ' + self . render_name
2023-06-09 14:43:40 -07:00
if self . nested and space_name in family . consts :
self . struct_name + = ' _ '
2023-01-20 09:50:36 -08:00
self . ptr_name = self . struct_name + ' * '
2023-12-13 15:14:29 -08:00
# All attr sets this one contains, directly or multiple levels down
self . child_nests = set ( )
2023-01-20 09:50:36 -08:00
self . request = False
self . reply = False
2023-12-13 15:14:29 -08:00
self . recursive = False
2023-01-20 09:50:36 -08:00
self . attr_list = [ ]
self . attrs = dict ( )
2023-08-23 17:30:55 -07:00
if type_list is not None :
2023-01-20 09:50:36 -08:00
for t in type_list :
self . attr_list . append ( ( t , self . attr_set [ t ] ) , )
else :
for t in self . attr_set :
self . attr_list . append ( ( t , self . attr_set [ t ] ) , )
max_val = 0
self . attr_max_val = None
for name , attr in self . attr_list :
2023-02-23 10:31:39 -08:00
if attr . value > = max_val :
2023-01-20 09:50:36 -08:00
max_val = attr . value
self . attr_max_val = attr
self . attrs [ name ] = attr
def __iter__ ( self ) :
yield from self . attrs
def __getitem__ ( self , key ) :
return self . attrs [ key ]
def member_list ( self ) :
return self . attr_list
def set_inherited ( self , new_inherited ) :
if self . _inherited != new_inherited :
raise Exception ( " Inheriting different members not supported " )
self . inherited = [ c_lower ( x ) for x in sorted ( self . _inherited ) ]
2023-03-07 16:39:22 -08:00
class EnumEntry ( SpecEnumEntry ) :
2023-01-20 09:50:36 -08:00
def __init__ ( self , enum_set , yaml , prev , value_start ) :
2023-03-07 16:39:22 -08:00
super ( ) . __init__ ( enum_set , yaml , prev , value_start )
if prev :
self . value_change = ( self . value != prev . value + 1 )
2023-01-20 09:50:36 -08:00
else :
self . value_change = ( self . value != 0 )
2023-01-25 16:02:33 -08:00
self . value_change = self . value_change or self . enum_set [ ' type ' ] == ' flags '
2023-03-07 16:39:22 -08:00
# Added by resolve:
self . c_name = None
delattr ( self , " c_name " )
2023-01-20 09:50:36 -08:00
2023-03-07 16:39:22 -08:00
def resolve ( self ) :
self . resolve_up ( super ( ) )
2023-01-25 16:02:33 -08:00
2023-03-07 16:39:22 -08:00
self . c_name = c_upper ( self . enum_set . value_pfx + self . name )
2023-01-25 16:02:33 -08:00
2023-01-20 09:50:36 -08:00
2023-03-07 16:39:22 -08:00
class EnumSet ( SpecEnumSet ) :
2023-01-20 09:50:36 -08:00
def __init__ ( self , family , yaml ) :
self . render_name = c_lower ( family . name + ' - ' + yaml [ ' name ' ] )
2023-06-09 14:43:39 -07:00
if ' enum-name ' in yaml :
if yaml [ ' enum-name ' ] :
self . enum_name = ' enum ' + c_lower ( yaml [ ' enum-name ' ] )
2023-11-22 19:10:50 -08:00
self . user_type = self . enum_name
2023-06-09 14:43:39 -07:00
else :
self . enum_name = None
else :
self . enum_name = ' enum ' + self . render_name
2023-01-20 09:50:36 -08:00
2023-11-22 19:10:50 -08:00
if self . enum_name :
self . user_type = self . enum_name
else :
self . user_type = ' int '
2023-01-20 09:50:36 -08:00
self . value_pfx = yaml . get ( ' name-prefix ' , f " { family . name } - { yaml [ ' name ' ] } - " )
2023-03-07 16:39:22 -08:00
super ( ) . __init__ ( family , yaml )
2023-01-20 09:50:36 -08:00
2023-03-07 16:39:22 -08:00
def new_entry ( self , entry , prev_entry , value_start ) :
return EnumEntry ( self , entry , prev_entry , value_start )
2023-01-20 09:50:36 -08:00
2023-06-12 08:59:19 -07:00
def value_range ( self ) :
low = min ( [ x . value for x in self . entries . values ( ) ] )
high = max ( [ x . value for x in self . entries . values ( ) ] )
if high - low + 1 != len ( self . entries ) :
raise Exception ( " Can ' t get value range for a noncontiguous enum " )
return low , high
2023-01-20 09:50:36 -08:00
2023-01-30 18:33:44 -08:00
class AttrSet ( SpecAttrSet ) :
2023-01-20 09:50:36 -08:00
def __init__ ( self , family , yaml ) :
2023-01-30 18:33:44 -08:00
super ( ) . __init__ ( family , yaml )
2023-01-20 09:50:36 -08:00
2023-01-30 18:33:44 -08:00
if self . subset_of is None :
2023-01-20 09:50:36 -08:00
if ' name-prefix ' in yaml :
pfx = yaml [ ' name-prefix ' ]
elif self . name == family . name :
pfx = family . name + ' -a- '
else :
pfx = f " { family . name } -a- { self . name } - "
self . name_prefix = c_upper ( pfx )
self . max_name = c_upper ( self . yaml . get ( ' attr-max-name ' , f " { self . name_prefix } max " ) )
2023-10-25 11:27:39 -07:00
self . cnt_name = c_upper ( self . yaml . get ( ' attr-cnt-name ' , f " __ { self . name_prefix } max " ) )
2023-01-20 09:50:36 -08:00
else :
self . name_prefix = family . attr_sets [ self . subset_of ] . name_prefix
self . max_name = family . attr_sets [ self . subset_of ] . max_name
2023-10-25 11:27:39 -07:00
self . cnt_name = family . attr_sets [ self . subset_of ] . cnt_name
2023-01-20 09:50:36 -08:00
2023-01-30 18:33:44 -08:00
# Added by resolve:
self . c_name = None
delattr ( self , " c_name " )
def resolve ( self ) :
2023-01-20 09:50:36 -08:00
self . c_name = c_lower ( self . name )
if self . c_name in _C_KW :
self . c_name + = ' _ '
2023-01-30 18:33:44 -08:00
if self . c_name == self . family . c_name :
2023-01-20 09:50:36 -08:00
self . c_name = ' '
2023-01-30 18:33:44 -08:00
def new_attr ( self , elem , value ) :
2023-06-12 08:59:20 -07:00
if elem [ ' type ' ] in scalars :
t = TypeScalar ( self . family , self , elem , value )
2023-01-30 18:33:44 -08:00
elif elem [ ' type ' ] == ' unused ' :
2023-06-12 08:59:20 -07:00
t = TypeUnused ( self . family , self , elem , value )
2023-01-30 18:33:44 -08:00
elif elem [ ' type ' ] == ' pad ' :
2023-06-12 08:59:20 -07:00
t = TypePad ( self . family , self , elem , value )
2023-01-30 18:33:44 -08:00
elif elem [ ' type ' ] == ' flag ' :
2023-06-12 08:59:20 -07:00
t = TypeFlag ( self . family , self , elem , value )
2023-01-30 18:33:44 -08:00
elif elem [ ' type ' ] == ' string ' :
2023-06-12 08:59:20 -07:00
t = TypeString ( self . family , self , elem , value )
2023-01-30 18:33:44 -08:00
elif elem [ ' type ' ] == ' binary ' :
2023-06-12 08:59:20 -07:00
t = TypeBinary ( self . family , self , elem , value )
2023-10-21 13:27:03 +02:00
elif elem [ ' type ' ] == ' bitfield32 ' :
t = TypeBitfield32 ( self . family , self , elem , value )
2023-01-30 18:33:44 -08:00
elif elem [ ' type ' ] == ' nest ' :
2023-06-12 08:59:20 -07:00
t = TypeNest ( self . family , self , elem , value )
2023-01-30 18:33:44 -08:00
elif elem [ ' type ' ] == ' array-nest ' :
2023-06-12 08:59:20 -07:00
t = TypeArrayNest ( self . family , self , elem , value )
2023-01-30 18:33:44 -08:00
elif elem [ ' type ' ] == ' nest-type-value ' :
2023-06-12 08:59:20 -07:00
t = TypeNestTypeValue ( self . family , self , elem , value )
2023-01-30 18:33:44 -08:00
else :
raise Exception ( f " No typed class for type { elem [ ' type ' ] } " )
2023-01-20 09:50:36 -08:00
2023-06-12 08:59:20 -07:00
if ' multi-attr ' in elem and elem [ ' multi-attr ' ] :
t = TypeMultiAttr ( self . family , self , elem , value , t )
return t
2023-01-20 09:50:36 -08:00
2023-01-30 18:33:44 -08:00
class Operation ( SpecOperation ) :
def __init__ ( self , family , yaml , req_value , rsp_value ) :
super ( ) . __init__ ( family , yaml , req_value , rsp_value )
2023-01-20 09:50:36 -08:00
2023-11-22 19:08:44 -08:00
self . render_name = c_lower ( family . name + ' _ ' + self . name )
2023-01-20 09:50:36 -08:00
self . dual_policy = ( ' do ' in yaml and ' request ' in yaml [ ' do ' ] ) and \
( ' dump ' in yaml and ' request ' in yaml [ ' dump ' ] )
2023-06-08 14:11:57 -07:00
self . has_ntf = False
2023-01-30 18:33:44 -08:00
# Added by resolve:
self . enum_name = None
delattr ( self , " enum_name " )
2023-01-20 09:50:36 -08:00
2023-01-30 18:33:44 -08:00
def resolve ( self ) :
self . resolve_up ( super ( ) )
if not self . is_async :
self . enum_name = self . family . op_prefix + c_upper ( self . name )
else :
self . enum_name = self . family . async_op_prefix + c_upper ( self . name )
2023-01-20 09:50:36 -08:00
2023-06-08 14:11:57 -07:00
def mark_has_ntf ( self ) :
self . has_ntf = True
2023-01-20 09:50:36 -08:00
2023-01-30 18:33:44 -08:00
class Family ( SpecFamily ) :
2023-06-09 14:43:35 -07:00
def __init__ ( self , file_name , exclude_ops ) :
2023-01-30 18:33:44 -08:00
# Added by resolve:
self . c_name = None
delattr ( self , " c_name " )
self . op_prefix = None
delattr ( self , " op_prefix " )
self . async_op_prefix = None
delattr ( self , " async_op_prefix " )
self . mcgrps = None
delattr ( self , " mcgrps " )
self . consts = None
delattr ( self , " consts " )
self . hooks = None
delattr ( self , " hooks " )
2023-06-09 14:43:35 -07:00
super ( ) . __init__ ( file_name , exclude_ops = exclude_ops )
2023-01-20 09:50:36 -08:00
self . fam_key = c_upper ( self . yaml . get ( ' c-family-name ' , self . yaml [ " name " ] + ' _FAMILY_NAME ' ) )
self . ver_key = c_upper ( self . yaml . get ( ' c-version-name ' , self . yaml [ " name " ] + ' _FAMILY_VERSION ' ) )
if ' definitions ' not in self . yaml :
self . yaml [ ' definitions ' ] = [ ]
if ' uapi-header ' in self . yaml :
self . uapi_header = self . yaml [ ' uapi-header ' ]
else :
self . uapi_header = f " linux/ { self . name } .h "
2023-10-03 15:57:35 -07:00
if self . uapi_header . startswith ( " linux/ " ) and self . uapi_header . endswith ( ' .h ' ) :
self . uapi_header_name = self . uapi_header [ 6 : - 2 ]
else :
self . uapi_header_name = self . name
2023-01-30 18:33:44 -08:00
def resolve ( self ) :
self . resolve_up ( super ( ) )
if self . yaml . get ( ' protocol ' , ' genetlink ' ) not in { ' genetlink ' , ' genetlink-c ' , ' genetlink-legacy ' } :
raise Exception ( " Codegen only supported for genetlink " )
self . c_name = c_lower ( self . name )
2023-01-20 09:50:36 -08:00
if ' name-prefix ' in self . yaml [ ' operations ' ] :
self . op_prefix = c_upper ( self . yaml [ ' operations ' ] [ ' name-prefix ' ] )
else :
self . op_prefix = c_upper ( self . yaml [ ' name ' ] + ' -cmd- ' )
if ' async-prefix ' in self . yaml [ ' operations ' ] :
self . async_op_prefix = c_upper ( self . yaml [ ' operations ' ] [ ' async-prefix ' ] )
else :
self . async_op_prefix = self . op_prefix
self . mcgrps = self . yaml . get ( ' mcast-groups ' , { ' list ' : [ ] } )
self . hooks = dict ( )
for when in [ ' pre ' , ' post ' ] :
self . hooks [ when ] = dict ( )
for op_mode in [ ' do ' , ' dump ' ] :
self . hooks [ when ] [ op_mode ] = dict ( )
self . hooks [ when ] [ op_mode ] [ ' set ' ] = set ( )
self . hooks [ when ] [ op_mode ] [ ' list ' ] = [ ]
# dict space-name -> 'request': set(attrs), 'reply': set(attrs)
self . root_sets = dict ( )
# dict space-name -> set('request', 'reply')
self . pure_nested_structs = dict ( )
2023-06-08 14:11:57 -07:00
self . _mark_notify ( )
2023-01-20 09:50:36 -08:00
self . _mock_up_events ( )
self . _load_root_sets ( )
self . _load_nested_sets ( )
2023-10-18 09:39:15 -07:00
self . _load_attr_use ( )
2023-01-20 09:50:36 -08:00
self . _load_hooks ( )
self . kernel_policy = self . yaml . get ( ' kernel-policy ' , ' split ' )
if self . kernel_policy == ' global ' :
self . _load_global_policy ( )
2023-03-07 16:39:22 -08:00
def new_enum ( self , elem ) :
return EnumSet ( self , elem )
2023-01-30 18:33:44 -08:00
def new_attr_set ( self , elem ) :
return AttrSet ( self , elem )
2023-01-20 09:50:36 -08:00
2023-01-30 18:33:44 -08:00
def new_operation ( self , elem , req_value , rsp_value ) :
return Operation ( self , elem , req_value , rsp_value )
2023-01-20 09:50:36 -08:00
2023-06-08 14:11:57 -07:00
def _mark_notify ( self ) :
for op in self . msgs . values ( ) :
if ' notify ' in op :
self . ops [ op [ ' notify ' ] ] . mark_has_ntf ( )
2023-01-20 09:50:36 -08:00
# Fake a 'do' equivalent of all events, so that we can render their response parsing
def _mock_up_events ( self ) :
for op in self . yaml [ ' operations ' ] [ ' list ' ] :
if ' event ' in op :
op [ ' do ' ] = {
' reply ' : {
' attributes ' : op [ ' event ' ] [ ' attributes ' ]
}
}
def _load_root_sets ( self ) :
2023-06-08 14:11:58 -07:00
for op_name , op in self . msgs . items ( ) :
2023-01-20 09:50:36 -08:00
if ' attribute-set ' not in op :
continue
req_attrs = set ( )
rsp_attrs = set ( )
for op_mode in [ ' do ' , ' dump ' ] :
if op_mode in op and ' request ' in op [ op_mode ] :
req_attrs . update ( set ( op [ op_mode ] [ ' request ' ] [ ' attributes ' ] ) )
if op_mode in op and ' reply ' in op [ op_mode ] :
rsp_attrs . update ( set ( op [ op_mode ] [ ' reply ' ] [ ' attributes ' ] ) )
2023-06-08 14:11:58 -07:00
if ' event ' in op :
rsp_attrs . update ( set ( op [ ' event ' ] [ ' attributes ' ] ) )
2023-01-20 09:50:36 -08:00
if op [ ' attribute-set ' ] not in self . root_sets :
self . root_sets [ op [ ' attribute-set ' ] ] = { ' request ' : req_attrs , ' reply ' : rsp_attrs }
else :
self . root_sets [ op [ ' attribute-set ' ] ] [ ' request ' ] . update ( req_attrs )
self . root_sets [ op [ ' attribute-set ' ] ] [ ' reply ' ] . update ( rsp_attrs )
2023-12-13 15:14:30 -08:00
def _sort_pure_types ( self ) :
# Try to reorder according to dependencies
pns_key_list = list ( self . pure_nested_structs . keys ( ) )
pns_key_seen = set ( )
rounds = len ( pns_key_list ) * * 2 # it's basically bubble sort
for _ in range ( rounds ) :
if len ( pns_key_list ) == 0 :
break
name = pns_key_list . pop ( 0 )
finished = True
for _ , spec in self . attr_sets [ name ] . items ( ) :
if ' nested-attributes ' in spec :
nested = spec [ ' nested-attributes ' ]
# If the unknown nest we hit is recursive it's fine, it'll be a pointer
if self . pure_nested_structs [ nested ] . recursive :
continue
if nested not in pns_key_seen :
# Dicts are sorted, this will make struct last
struct = self . pure_nested_structs . pop ( name )
self . pure_nested_structs [ name ] = struct
finished = False
break
if finished :
pns_key_seen . add ( name )
else :
pns_key_list . append ( name )
2023-01-20 09:50:36 -08:00
def _load_nested_sets ( self ) :
2023-06-07 13:23:59 -07:00
attr_set_queue = list ( self . root_sets . keys ( ) )
attr_set_seen = set ( self . root_sets . keys ( ) )
while len ( attr_set_queue ) :
a_set = attr_set_queue . pop ( 0 )
for attr , spec in self . attr_sets [ a_set ] . items ( ) :
if ' nested-attributes ' not in spec :
continue
nested = spec [ ' nested-attributes ' ]
if nested not in attr_set_seen :
attr_set_queue . append ( nested )
attr_set_seen . add ( nested )
inherit = set ( )
if nested not in self . root_sets :
if nested not in self . pure_nested_structs :
self . pure_nested_structs [ nested ] = Struct ( self , nested , inherited = inherit )
else :
raise Exception ( f ' Using attr set as root and nested not supported - { nested } ' )
if ' type-value ' in spec :
if nested in self . root_sets :
raise Exception ( " Inheriting members to a space used as root not supported " )
inherit . update ( set ( spec [ ' type-value ' ] ) )
elif spec [ ' type ' ] == ' array-nest ' :
inherit . add ( ' idx ' )
self . pure_nested_structs [ nested ] . set_inherited ( inherit )
2023-01-20 09:50:36 -08:00
for root_set , rs_members in self . root_sets . items ( ) :
for attr , spec in self . attr_sets [ root_set ] . items ( ) :
if ' nested-attributes ' in spec :
nested = spec [ ' nested-attributes ' ]
if attr in rs_members [ ' request ' ] :
self . pure_nested_structs [ nested ] . request = True
if attr in rs_members [ ' reply ' ] :
self . pure_nested_structs [ nested ] . reply = True
2023-12-13 15:14:30 -08:00
self . _sort_pure_types ( )
2023-12-13 15:14:29 -08:00
# Propagate the request / reply / recursive
2023-06-07 13:23:58 -07:00
for attr_set , struct in reversed ( self . pure_nested_structs . items ( ) ) :
for _ , spec in self . attr_sets [ attr_set ] . items ( ) :
if ' nested-attributes ' in spec :
2023-12-13 15:14:29 -08:00
child_name = spec [ ' nested-attributes ' ]
struct . child_nests . add ( child_name )
child = self . pure_nested_structs . get ( child_name )
2023-06-07 13:23:58 -07:00
if child :
2023-12-13 15:14:29 -08:00
if not child . recursive :
struct . child_nests . update ( child . child_nests )
2023-06-07 13:23:58 -07:00
child . request | = struct . request
child . reply | = struct . reply
2023-12-13 15:14:29 -08:00
if attr_set in struct . child_nests :
struct . recursive = True
2023-06-07 13:23:57 -07:00
2023-12-13 15:14:30 -08:00
self . _sort_pure_types ( )
2023-10-18 09:39:15 -07:00
def _load_attr_use ( self ) :
for _ , struct in self . pure_nested_structs . items ( ) :
if struct . request :
for _ , arg in struct . member_list ( ) :
arg . request = True
if struct . reply :
for _ , arg in struct . member_list ( ) :
arg . reply = True
for root_set , rs_members in self . root_sets . items ( ) :
for attr , spec in self . attr_sets [ root_set ] . items ( ) :
if attr in rs_members [ ' request ' ] :
spec . request = True
if attr in rs_members [ ' reply ' ] :
spec . reply = True
2023-01-20 09:50:36 -08:00
def _load_global_policy ( self ) :
global_set = set ( )
attr_set_name = None
for op_name , op in self . ops . items ( ) :
if not op :
continue
if ' attribute-set ' not in op :
continue
if attr_set_name is None :
attr_set_name = op [ ' attribute-set ' ]
if attr_set_name != op [ ' attribute-set ' ] :
raise Exception ( ' For a global policy all ops must use the same set ' )
2023-01-30 18:33:41 -08:00
for op_mode in [ ' do ' , ' dump ' ] :
2023-01-20 09:50:36 -08:00
if op_mode in op :
2023-08-23 17:30:54 -07:00
req = op [ op_mode ] . get ( ' request ' )
if req :
global_set . update ( req . get ( ' attributes ' , [ ] ) )
2023-01-20 09:50:36 -08:00
self . global_policy = [ ]
self . global_policy_set = attr_set_name
for attr in self . attr_sets [ attr_set_name ] :
if attr in global_set :
self . global_policy . append ( attr )
def _load_hooks ( self ) :
for op in self . ops . values ( ) :
for op_mode in [ ' do ' , ' dump ' ] :
if op_mode not in op :
continue
for when in [ ' pre ' , ' post ' ] :
if when not in op [ op_mode ] :
continue
name = op [ op_mode ] [ when ]
if name in self . hooks [ when ] [ op_mode ] [ ' set ' ] :
continue
self . hooks [ when ] [ op_mode ] [ ' set ' ] . add ( name )
self . hooks [ when ] [ op_mode ] [ ' list ' ] . append ( name )
class RenderInfo :
2023-06-08 14:11:59 -07:00
def __init__ ( self , cw , family , ku_space , op , op_mode , attr_set = None ) :
2023-01-20 09:50:36 -08:00
self . family = family
self . nl = cw . nlib
self . ku_space = ku_space
2023-06-08 14:11:57 -07:00
self . op_mode = op_mode
2023-01-20 09:50:36 -08:00
self . op = op
2023-12-13 15:14:27 -08:00
self . fixed_hdr = None
if op and op . fixed_header :
self . fixed_hdr = ' struct ' + c_lower ( op . fixed_header )
2023-01-20 09:50:36 -08:00
# 'do' and 'dump' response parsing is identical
2023-06-01 19:35:42 -07:00
self . type_consistent = True
2023-10-21 13:27:04 +02:00
if op_mode != ' do ' and ' dump ' in op :
if ' do ' in op :
if ( ' reply ' in op [ ' do ' ] ) != ( ' reply ' in op [ " dump " ] ) :
self . type_consistent = False
elif ' reply ' in op [ ' do ' ] and op [ " do " ] [ " reply " ] != op [ " dump " ] [ " reply " ] :
self . type_consistent = False
else :
2023-06-01 19:35:42 -07:00
self . type_consistent = False
2023-01-20 09:50:36 -08:00
self . attr_set = attr_set
if not self . attr_set :
self . attr_set = op [ ' attribute-set ' ]
2023-06-09 14:43:40 -07:00
self . type_name_conflict = False
2023-01-20 09:50:36 -08:00
if op :
2023-06-08 14:11:59 -07:00
self . type_name = c_lower ( op . name )
2023-01-20 09:50:36 -08:00
else :
self . type_name = c_lower ( attr_set )
2023-06-09 14:43:40 -07:00
if attr_set in family . consts :
self . type_name_conflict = True
2023-01-20 09:50:36 -08:00
self . cw = cw
self . struct = dict ( )
2023-06-08 14:11:57 -07:00
if op_mode == ' notify ' :
op_mode = ' do '
2023-01-20 09:50:36 -08:00
for op_dir in [ ' request ' , ' reply ' ] :
2023-10-06 06:50:32 -07:00
if op :
type_list = [ ]
if op_dir in op [ op_mode ] :
type_list = op [ op_mode ] [ op_dir ] [ ' attributes ' ]
self . struct [ op_dir ] = Struct ( family , self . attr_set , type_list = type_list )
2023-01-20 09:50:36 -08:00
if op_mode == ' event ' :
self . struct [ ' reply ' ] = Struct ( family , self . attr_set , type_list = op [ ' event ' ] [ ' attributes ' ] )
class CodeWriter :
2023-11-29 11:36:22 -08:00
def __init__ ( self , nlib , out_file = None , overwrite = True ) :
2023-01-20 09:50:36 -08:00
self . nlib = nlib
2023-11-29 11:36:22 -08:00
self . _overwrite = overwrite
2023-01-20 09:50:36 -08:00
self . _nl = False
2023-06-08 14:11:52 -07:00
self . _block_end = False
2023-01-20 09:50:36 -08:00
self . _silent_block = False
self . _ind = 0
2023-10-25 09:22:53 -07:00
self . _ifdef_block = None
2023-08-24 14:24:31 -07:00
if out_file is None :
self . _out = os . sys . stdout
else :
2023-10-27 15:34:08 -07:00
self . _out = tempfile . NamedTemporaryFile ( ' w+ ' )
2023-08-24 14:24:31 -07:00
self . _out_file = out_file
def __del__ ( self ) :
self . close_out_file ( )
def close_out_file ( self ) :
if self . _out == os . sys . stdout :
return
2023-10-27 15:34:08 -07:00
# Avoid modifying the file if contents didn't change
self . _out . flush ( )
2023-11-29 11:36:22 -08:00
if not self . _overwrite and os . path . isfile ( self . _out_file ) :
if filecmp . cmp ( self . _out . name , self . _out_file , shallow = False ) :
return
2023-08-24 14:24:31 -07:00
with open ( self . _out_file , ' w+ ' ) as out_file :
self . _out . seek ( 0 )
shutil . copyfileobj ( self . _out , out_file )
self . _out . close ( )
self . _out = os . sys . stdout
2023-01-20 09:50:36 -08:00
@classmethod
def _is_cond ( cls , line ) :
return line . startswith ( ' if ' ) or line . startswith ( ' while ' ) or line . startswith ( ' for ' )
2023-06-08 14:11:52 -07:00
def p ( self , line , add_ind = 0 ) :
if self . _block_end :
self . _block_end = False
if line . startswith ( ' else ' ) :
line = ' } ' + line
else :
self . _out . write ( ' \t ' * self . _ind + ' } \n ' )
2023-01-20 09:50:36 -08:00
if self . _nl :
2023-06-08 14:11:52 -07:00
self . _out . write ( ' \n ' )
2023-01-20 09:50:36 -08:00
self . _nl = False
2023-06-08 14:11:52 -07:00
2023-01-20 09:50:36 -08:00
ind = self . _ind
if line [ - 1 ] == ' : ' :
ind - = 1
if self . _silent_block :
ind + = 1
self . _silent_block = line . endswith ( ' ) ' ) and CodeWriter . _is_cond ( line )
2023-10-25 09:22:53 -07:00
if line [ 0 ] == ' # ' :
ind = 0
2023-01-20 09:50:36 -08:00
if add_ind :
ind + = add_ind
self . _out . write ( ' \t ' * ind + line + ' \n ' )
def nl ( self ) :
self . _nl = True
def block_start ( self , line = ' ' ) :
if line :
line = line + ' '
self . p ( line + ' { ' )
self . _ind + = 1
def block_end ( self , line = ' ' ) :
if line and line [ 0 ] not in { ' ; ' , ' , ' } :
line = ' ' + line
self . _ind - = 1
2023-06-08 14:11:52 -07:00
self . _nl = False
if not line :
# Delay printing closing bracket in case "else" comes next
if self . _block_end :
self . _out . write ( ' \t ' * ( self . _ind + 1 ) + ' } \n ' )
self . _block_end = True
else :
self . p ( ' } ' + line )
2023-01-20 09:50:36 -08:00
def write_doc_line ( self , doc , indent = True ) :
words = doc . split ( )
line = ' * '
for word in words :
if len ( line ) + len ( word ) > = 79 :
self . p ( line )
line = ' * '
if indent :
line + = ' '
line + = ' ' + word
self . p ( line )
def write_func_prot ( self , qual_ret , name , args = None , doc = None , suffix = ' ' ) :
if not args :
args = [ ' void ' ]
if doc :
self . p ( ' /* ' )
self . p ( ' * ' + doc )
self . p ( ' */ ' )
oneline = qual_ret
if qual_ret [ - 1 ] != ' * ' :
oneline + = ' '
oneline + = f " { name } ( { ' , ' . join ( args ) } ) { suffix } "
if len ( oneline ) < 80 :
self . p ( oneline )
return
v = qual_ret
if len ( v ) > 3 :
self . p ( v )
v = ' '
elif qual_ret [ - 1 ] != ' * ' :
v + = ' '
v + = name + ' ( '
ind = ' \t ' * ( len ( v ) / / 8 ) + ' ' * ( len ( v ) % 8 )
delta_ind = len ( v ) - len ( ind )
v + = args [ 0 ]
i = 1
while i < len ( args ) :
next_len = len ( v ) + len ( args [ i ] )
if v [ 0 ] == ' \t ' :
next_len + = delta_ind
if next_len > 76 :
self . p ( v + ' , ' )
v = ind
else :
v + = ' , '
v + = args [ i ]
i + = 1
self . p ( v + ' ) ' + suffix )
def write_func_lvar ( self , local_vars ) :
if not local_vars :
return
if type ( local_vars ) is str :
local_vars = [ local_vars ]
local_vars . sort ( key = len , reverse = True )
for var in local_vars :
self . p ( var )
self . nl ( )
def write_func ( self , qual_ret , name , body , args = None , local_vars = None ) :
self . write_func_prot ( qual_ret = qual_ret , name = name , args = args )
self . write_func_lvar ( local_vars = local_vars )
self . block_start ( )
for line in body :
self . p ( line )
self . block_end ( )
def writes_defines ( self , defines ) :
longest = 0
for define in defines :
if len ( define [ 0 ] ) > longest :
longest = len ( define [ 0 ] )
longest = ( ( longest + 8 ) / / 8 ) * 8
for define in defines :
line = ' #define ' + define [ 0 ]
line + = ' \t ' * ( ( longest - len ( define [ 0 ] ) + 7 ) / / 8 )
if type ( define [ 1 ] ) is int :
line + = str ( define [ 1 ] )
elif type ( define [ 1 ] ) is str :
line + = ' " ' + define [ 1 ] + ' " '
self . p ( line )
def write_struct_init ( self , members ) :
longest = max ( [ len ( x [ 0 ] ) for x in members ] )
longest + = 1 # because we prepend a .
longest = ( ( longest + 8 ) / / 8 ) * 8
for one in members :
line = ' . ' + one [ 0 ]
line + = ' \t ' * ( ( longest - len ( one [ 0 ] ) - 1 + 7 ) / / 8 )
2023-10-18 09:39:16 -07:00
line + = ' = ' + str ( one [ 1 ] ) + ' , '
2023-01-20 09:50:36 -08:00
self . p ( line )
2023-10-25 09:22:53 -07:00
def ifdef_block ( self , config ) :
config_option = None
if config :
config_option = ' CONFIG_ ' + c_upper ( config )
if self . _ifdef_block == config_option :
return
if self . _ifdef_block :
self . p ( ' #endif /* ' + self . _ifdef_block + ' */ ' )
if config_option :
self . p ( ' #ifdef ' + config_option )
self . _ifdef_block = config_option
2023-01-20 09:50:36 -08:00
2023-10-18 14:39:21 -07:00
scalars = { ' u8 ' , ' u16 ' , ' u32 ' , ' u64 ' , ' s32 ' , ' s64 ' , ' uint ' , ' sint ' }
2023-01-20 09:50:36 -08:00
direction_to_suffix = {
' reply ' : ' _rsp ' ,
' request ' : ' _req ' ,
' ' : ' '
}
op_mode_to_wrapper = {
' do ' : ' ' ,
' dump ' : ' _list ' ,
' notify ' : ' _ntf ' ,
' event ' : ' ' ,
}
_C_KW = {
2023-06-08 14:11:51 -07:00
' auto ' ,
' bool ' ,
' break ' ,
' case ' ,
' char ' ,
' const ' ,
' continue ' ,
' default ' ,
' do ' ,
' double ' ,
' else ' ,
' enum ' ,
' extern ' ,
' float ' ,
' for ' ,
' goto ' ,
' if ' ,
' inline ' ,
' int ' ,
' long ' ,
' register ' ,
' return ' ,
' short ' ,
' signed ' ,
' sizeof ' ,
' static ' ,
' struct ' ,
' switch ' ,
' typedef ' ,
' union ' ,
' unsigned ' ,
' void ' ,
' volatile ' ,
' while '
2023-01-20 09:50:36 -08:00
}
def rdir ( direction ) :
if direction == ' reply ' :
return ' request '
if direction == ' request ' :
return ' reply '
return direction
def op_prefix ( ri , direction , deref = False ) :
suffix = f " _ { ri . type_name } "
if not ri . op_mode or ri . op_mode == ' do ' :
suffix + = f " { direction_to_suffix [ direction ] } "
else :
if direction == ' request ' :
suffix + = ' _req_dump '
else :
if ri . type_consistent :
if deref :
suffix + = f " { direction_to_suffix [ direction ] } "
else :
suffix + = op_mode_to_wrapper [ ri . op_mode ]
else :
suffix + = ' _rsp '
suffix + = ' _dump ' if deref else ' _list '
2023-11-22 19:08:44 -08:00
return f " { ri . family . c_name } { suffix } "
2023-01-20 09:50:36 -08:00
def type_name ( ri , direction , deref = False ) :
return f " struct { op_prefix ( ri , direction , deref = deref ) } "
def print_prototype ( ri , direction , terminate = True , doc = None ) :
suffix = ' ; ' if terminate else ' '
fname = ri . op . render_name
if ri . op_mode == ' dump ' :
fname + = ' _dump '
args = [ ' struct ynl_sock *ys ' ]
if ' request ' in ri . op [ ri . op_mode ] :
args . append ( f " { type_name ( ri , direction ) } * " + f " { direction_to_suffix [ direction ] [ 1 : ] } " )
ret = ' int '
if ' reply ' in ri . op [ ri . op_mode ] :
ret = f " { type_name ( ri , rdir ( direction ) ) } * "
ri . cw . write_func_prot ( ret , fname , args , doc = doc , suffix = suffix )
def print_req_prototype ( ri ) :
print_prototype ( ri , " request " , doc = ri . op [ ' doc ' ] )
def print_dump_prototype ( ri ) :
print_prototype ( ri , " request " )
2023-12-13 15:14:32 -08:00
def put_typol_fwd ( cw , struct ) :
cw . p ( f ' extern struct ynl_policy_nest { struct . render_name } _nest; ' )
2023-01-20 09:50:36 -08:00
def put_typol ( cw , struct ) :
type_max = struct . attr_set . max_name
cw . block_start ( line = f ' struct ynl_policy_attr { struct . render_name } _policy[ { type_max } + 1] = ' )
for _ , arg in struct . member_list ( ) :
arg . attr_typol ( cw )
cw . block_end ( line = ' ; ' )
cw . nl ( )
cw . block_start ( line = f ' struct ynl_policy_nest { struct . render_name } _nest = ' )
cw . p ( f ' .max_attr = { type_max } , ' )
cw . p ( f ' .table = { struct . render_name } _policy, ' )
cw . block_end ( line = ' ; ' )
cw . nl ( )
2023-06-07 13:23:55 -07:00
def _put_enum_to_str_helper ( cw , render_name , map_name , arg_name , enum = None ) :
args = [ f ' int { arg_name } ' ]
2023-11-22 19:10:50 -08:00
if enum :
args = [ enum . user_type + ' ' + arg_name ]
2023-06-07 13:23:55 -07:00
cw . write_func_prot ( ' const char * ' , f ' { render_name } _str ' , args )
cw . block_start ( )
if enum and enum . type == ' flags ' :
cw . p ( f ' { arg_name } = ffs( { arg_name } ) - 1; ' )
2024-02-27 14:30:22 -08:00
cw . p ( f ' if ( { arg_name } < 0 || { arg_name } >= (int)YNL_ARRAY_SIZE( { map_name } )) ' )
2023-06-07 13:23:55 -07:00
cw . p ( ' return NULL; ' )
cw . p ( f ' return { map_name } [ { arg_name } ]; ' )
cw . block_end ( )
cw . nl ( )
2023-06-01 19:35:44 -07:00
def put_op_name_fwd ( family , cw ) :
2023-11-22 19:08:44 -08:00
cw . write_func_prot ( ' const char * ' , f ' { family . c_name } _op_str ' , [ ' int op ' ] , suffix = ' ; ' )
2023-06-01 19:35:44 -07:00
def put_op_name ( family , cw ) :
2023-11-22 19:08:44 -08:00
map_name = f ' { family . c_name } _op_strmap '
2023-06-01 19:35:44 -07:00
cw . block_start ( line = f " static const char * const { map_name } [] = " )
for op_name , op in family . msgs . items ( ) :
2023-06-07 13:23:54 -07:00
if op . rsp_value :
2023-11-22 19:05:58 -08:00
# Make sure we don't add duplicated entries, if multiple commands
# produce the same response in legacy families.
if family . rsp_by_value [ op . rsp_value ] != op :
cw . p ( f ' // skip " { op_name } " , duplicate reply value ' )
continue
2023-06-07 13:23:54 -07:00
if op . req_value == op . rsp_value :
cw . p ( f ' [ { op . enum_name } ] = " { op_name } " , ' )
else :
cw . p ( f ' [ { op . rsp_value } ] = " { op_name } " , ' )
2023-06-01 19:35:44 -07:00
cw . block_end ( line = ' ; ' )
cw . nl ( )
2023-11-22 19:08:44 -08:00
_put_enum_to_str_helper ( cw , family . c_name + ' _op ' , map_name , ' op ' )
2023-06-01 19:35:44 -07:00
def put_enum_to_str_fwd ( family , cw , enum ) :
2023-11-22 19:10:50 -08:00
args = [ enum . user_type + ' value ' ]
2023-06-01 19:35:44 -07:00
cw . write_func_prot ( ' const char * ' , f ' { enum . render_name } _str ' , args , suffix = ' ; ' )
def put_enum_to_str ( family , cw , enum ) :
map_name = f ' { enum . render_name } _strmap '
cw . block_start ( line = f " static const char * const { map_name } [] = " )
for entry in enum . entries . values ( ) :
cw . p ( f ' [ { entry . value } ] = " { entry . name } " , ' )
cw . block_end ( line = ' ; ' )
cw . nl ( )
2023-06-07 13:23:55 -07:00
_put_enum_to_str_helper ( cw , enum . render_name , map_name , ' value ' , enum = enum )
2023-06-01 19:35:44 -07:00
2023-12-13 15:14:32 -08:00
def put_req_nested_prototype ( ri , struct , suffix = ' ; ' ) :
2023-01-20 09:50:36 -08:00
func_args = [ ' struct nlmsghdr *nlh ' ,
' unsigned int attr_type ' ,
f ' { struct . ptr_name } obj ' ]
2023-12-13 15:14:32 -08:00
ri . cw . write_func_prot ( ' int ' , f ' { struct . render_name } _put ' , func_args ,
suffix = suffix )
def put_req_nested ( ri , struct ) :
put_req_nested_prototype ( ri , struct , suffix = ' ' )
2023-01-20 09:50:36 -08:00
ri . cw . block_start ( )
ri . cw . write_func_lvar ( ' struct nlattr *nest; ' )
2024-02-27 14:30:19 -08:00
ri . cw . p ( " nest = ynl_attr_nest_start(nlh, attr_type); " )
2023-01-20 09:50:36 -08:00
for _ , arg in struct . member_list ( ) :
arg . attr_put ( ri , " obj " )
2024-02-27 14:30:19 -08:00
ri . cw . p ( " ynl_attr_nest_end(nlh, nest); " )
2023-01-20 09:50:36 -08:00
ri . cw . nl ( )
ri . cw . p ( ' return 0; ' )
ri . cw . block_end ( )
ri . cw . nl ( )
def _multi_parse ( ri , struct , init_lines , local_vars ) :
if struct . nested :
2024-02-27 14:30:20 -08:00
iter_line = " ynl_attr_for_each_nested(attr, nested) "
2023-01-20 09:50:36 -08:00
else :
2023-12-13 15:14:27 -08:00
if ri . fixed_hdr :
local_vars + = [ ' void *hdr; ' ]
2024-02-27 14:30:20 -08:00
iter_line = " ynl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len) "
2023-01-20 09:50:36 -08:00
array_nests = set ( )
multi_attrs = set ( )
needs_parg = False
for arg , aspec in struct . member_list ( ) :
if aspec [ ' type ' ] == ' array-nest ' :
local_vars . append ( f ' const struct nlattr *attr_ { aspec . c_name } ; ' )
array_nests . add ( arg )
if ' multi-attr ' in aspec :
multi_attrs . add ( arg )
needs_parg | = ' nested-attributes ' in aspec
if array_nests or multi_attrs :
local_vars . append ( ' int i; ' )
if needs_parg :
local_vars . append ( ' struct ynl_parse_arg parg; ' )
init_lines . append ( ' parg.ys = yarg->ys; ' )
2023-06-06 12:43:01 -07:00
all_multi = array_nests | multi_attrs
for anest in sorted ( all_multi ) :
local_vars . append ( f " unsigned int n_ { struct [ anest ] . c_name } = 0; " )
2023-01-20 09:50:36 -08:00
ri . cw . block_start ( )
ri . cw . write_func_lvar ( local_vars )
for line in init_lines :
ri . cw . p ( line )
ri . cw . nl ( )
for arg in struct . inherited :
ri . cw . p ( f ' dst-> { arg } = { arg } ; ' )
2023-12-13 15:14:27 -08:00
if ri . fixed_hdr :
2024-02-27 14:30:21 -08:00
ri . cw . p ( ' hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr)); ' )
2023-12-13 15:14:27 -08:00
ri . cw . p ( f " memcpy(&dst->_hdr, hdr, sizeof( { ri . fixed_hdr } )); " )
2023-06-06 12:43:01 -07:00
for anest in sorted ( all_multi ) :
aspec = struct [ anest ]
ri . cw . p ( f " if (dst-> { aspec . c_name } ) " )
ri . cw . p ( f ' return ynl_error_parse(yarg, " attribute already present ( { struct . attr_set . name } . { aspec . name } ) " ); ' )
2023-01-20 09:50:36 -08:00
ri . cw . nl ( )
ri . cw . block_start ( line = iter_line )
2024-02-27 14:30:19 -08:00
ri . cw . p ( ' unsigned int type = ynl_attr_type(attr); ' )
2023-06-08 14:11:53 -07:00
ri . cw . nl ( )
2023-01-20 09:50:36 -08:00
first = True
for _ , arg in struct . member_list ( ) :
2023-06-01 19:35:40 -07:00
good = arg . attr_get ( ri , ' dst ' , first = first )
# First may be 'unused' or 'pad', ignore those
first & = not good
2023-01-20 09:50:36 -08:00
ri . cw . block_end ( )
ri . cw . nl ( )
for anest in sorted ( array_nests ) :
aspec = struct [ anest ]
2023-06-06 12:43:01 -07:00
ri . cw . block_start ( line = f " if (n_ { aspec . c_name } ) " )
ri . cw . p ( f " dst-> { aspec . c_name } = calloc( { aspec . c_name } , sizeof(*dst-> { aspec . c_name } )); " )
ri . cw . p ( f " dst->n_ { aspec . c_name } = n_ { aspec . c_name } ; " )
2023-01-20 09:50:36 -08:00
ri . cw . p ( ' i = 0; ' )
ri . cw . p ( f " parg.rsp_policy = & { aspec . nested_render_name } _nest; " )
2024-02-27 14:30:20 -08:00
ri . cw . block_start ( line = f " ynl_attr_for_each_nested(attr, attr_ { aspec . c_name } ) " )
2023-01-20 09:50:36 -08:00
ri . cw . p ( f " parg.data = &dst-> { aspec . c_name } [i]; " )
2024-02-27 14:30:19 -08:00
ri . cw . p ( f " if ( { aspec . nested_render_name } _parse(&parg, attr, ynl_attr_type(attr))) " )
2024-02-27 14:30:29 -08:00
ri . cw . p ( ' return YNL_PARSE_CB_ERROR; ' )
2023-01-20 09:50:36 -08:00
ri . cw . p ( ' i++; ' )
ri . cw . block_end ( )
ri . cw . block_end ( )
ri . cw . nl ( )
for anest in sorted ( multi_attrs ) :
aspec = struct [ anest ]
2023-06-06 12:43:01 -07:00
ri . cw . block_start ( line = f " if (n_ { aspec . c_name } ) " )
ri . cw . p ( f " dst-> { aspec . c_name } = calloc(n_ { aspec . c_name } , sizeof(*dst-> { aspec . c_name } )); " )
ri . cw . p ( f " dst->n_ { aspec . c_name } = n_ { aspec . c_name } ; " )
2023-01-20 09:50:36 -08:00
ri . cw . p ( ' i = 0; ' )
if ' nested-attributes ' in aspec :
ri . cw . p ( f " parg.rsp_policy = & { aspec . nested_render_name } _nest; " )
ri . cw . block_start ( line = iter_line )
2024-02-27 14:30:19 -08:00
ri . cw . block_start ( line = f " if (ynl_attr_type(attr) == { aspec . enum_name } ) " )
2023-01-20 09:50:36 -08:00
if ' nested-attributes ' in aspec :
ri . cw . p ( f " parg.data = &dst-> { aspec . c_name } [i]; " )
ri . cw . p ( f " if ( { aspec . nested_render_name } _parse(&parg, attr)) " )
2024-02-27 14:30:29 -08:00
ri . cw . p ( ' return YNL_PARSE_CB_ERROR; ' )
2023-10-18 14:39:19 -07:00
elif aspec . type in scalars :
2024-02-27 14:30:19 -08:00
ri . cw . p ( f " dst-> { aspec . c_name } [i] = ynl_attr_get_ { aspec . type } (attr); " )
2023-01-20 09:50:36 -08:00
else :
raise Exception ( ' Nest parsing type not supported yet ' )
ri . cw . p ( ' i++; ' )
ri . cw . block_end ( )
ri . cw . block_end ( )
ri . cw . block_end ( )
ri . cw . nl ( )
if struct . nested :
ri . cw . p ( ' return 0; ' )
else :
2024-02-27 14:30:29 -08:00
ri . cw . p ( ' return YNL_PARSE_CB_OK; ' )
2023-01-20 09:50:36 -08:00
ri . cw . block_end ( )
ri . cw . nl ( )
2023-12-13 15:14:32 -08:00
def parse_rsp_nested_prototype ( ri , struct , suffix = ' ; ' ) :
2023-01-20 09:50:36 -08:00
func_args = [ ' struct ynl_parse_arg *yarg ' ,
' const struct nlattr *nested ' ]
for arg in struct . inherited :
func_args . append ( ' __u32 ' + arg )
2023-12-13 15:14:32 -08:00
ri . cw . write_func_prot ( ' int ' , f ' { struct . render_name } _parse ' , func_args ,
suffix = suffix )
def parse_rsp_nested ( ri , struct ) :
parse_rsp_nested_prototype ( ri , struct , suffix = ' ' )
2023-01-20 09:50:36 -08:00
local_vars = [ ' const struct nlattr *attr; ' ,
f ' { struct . ptr_name } dst = yarg->data; ' ]
init_lines = [ ]
_multi_parse ( ri , struct , init_lines , local_vars )
def parse_rsp_msg ( ri , deref = False ) :
if ' reply ' not in ri . op [ ri . op_mode ] and ri . op_mode != ' event ' :
return
func_args = [ ' const struct nlmsghdr *nlh ' ,
2024-02-27 14:30:28 -08:00
' struct ynl_parse_arg *yarg ' ]
2023-01-20 09:50:36 -08:00
local_vars = [ f ' { type_name ( ri , " reply " , deref = deref ) } *dst; ' ,
' const struct nlattr *attr; ' ]
init_lines = [ ' dst = yarg->data; ' ]
ri . cw . write_func_prot ( ' int ' , f ' { op_prefix ( ri , " reply " , deref = deref ) } _parse ' , func_args )
2023-08-23 17:30:55 -07:00
if ri . struct [ " reply " ] . member_list ( ) :
_multi_parse ( ri , ri . struct [ " reply " ] , init_lines , local_vars )
else :
# Empty reply
ri . cw . block_start ( )
2024-02-27 14:30:29 -08:00
ri . cw . p ( ' return YNL_PARSE_CB_OK; ' )
2023-08-23 17:30:55 -07:00
ri . cw . block_end ( )
ri . cw . nl ( )
2023-01-20 09:50:36 -08:00
def print_req ( ri ) :
ret_ok = ' 0 '
ret_err = ' -1 '
direction = " request "
2023-11-26 14:58:58 -08:00
local_vars = [ ' struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; ' ,
' struct nlmsghdr *nlh; ' ,
2023-06-01 19:35:45 -07:00
' int err; ' ]
2023-01-20 09:50:36 -08:00
if ' reply ' in ri . op [ ri . op_mode ] :
ret_ok = ' rsp '
ret_err = ' NULL '
2023-11-26 14:58:58 -08:00
local_vars + = [ f ' { type_name ( ri , rdir ( direction ) ) } *rsp; ' ]
2023-01-20 09:50:36 -08:00
2023-12-13 15:14:27 -08:00
if ri . fixed_hdr :
local_vars + = [ ' size_t hdr_len; ' ,
' void *hdr; ' ]
2023-01-20 09:50:36 -08:00
print_prototype ( ri , direction , terminate = False )
ri . cw . block_start ( )
ri . cw . write_func_lvar ( local_vars )
ri . cw . p ( f " nlh = ynl_gemsg_start_req(ys, { ri . nl . get_family_id ( ) } , { ri . op . enum_name } , 1); " )
ri . cw . p ( f " ys->req_policy = & { ri . struct [ ' request ' ] . render_name } _nest; " )
if ' reply ' in ri . op [ ri . op_mode ] :
2023-06-01 19:35:45 -07:00
ri . cw . p ( f " yrs.yarg.rsp_policy = & { ri . struct [ ' reply ' ] . render_name } _nest; " )
2023-01-20 09:50:36 -08:00
ri . cw . nl ( )
2023-12-13 15:14:27 -08:00
if ri . fixed_hdr :
ri . cw . p ( " hdr_len = sizeof(req->_hdr); " )
2024-02-27 14:30:21 -08:00
ri . cw . p ( " hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len); " )
2023-12-13 15:14:27 -08:00
ri . cw . p ( " memcpy(hdr, &req->_hdr, hdr_len); " )
ri . cw . nl ( )
2023-01-20 09:50:36 -08:00
for _ , attr in ri . struct [ " request " ] . member_list ( ) :
attr . attr_put ( ri , " req " )
ri . cw . nl ( )
if ' reply ' in ri . op [ ri . op_mode ] :
ri . cw . p ( ' rsp = calloc(1, sizeof(*rsp)); ' )
2023-06-01 19:35:45 -07:00
ri . cw . p ( ' yrs.yarg.data = rsp; ' )
ri . cw . p ( f " yrs.cb = { op_prefix ( ri , ' reply ' ) } _parse; " )
if ri . op . value is not None :
ri . cw . p ( f ' yrs.rsp_cmd = { ri . op . enum_name } ; ' )
else :
ri . cw . p ( f ' yrs.rsp_cmd = { ri . op . rsp_value } ; ' )
2023-01-20 09:50:36 -08:00
ri . cw . nl ( )
2023-11-26 14:58:58 -08:00
ri . cw . p ( " err = ynl_exec(ys, nlh, &yrs); " )
2023-06-01 19:35:45 -07:00
ri . cw . p ( ' if (err < 0) ' )
if ' reply ' in ri . op [ ri . op_mode ] :
2023-01-20 09:50:36 -08:00
ri . cw . p ( ' goto err_free; ' )
2023-06-01 19:35:45 -07:00
else :
ri . cw . p ( ' return -1; ' )
2023-01-20 09:50:36 -08:00
ri . cw . nl ( )
2023-06-01 19:35:45 -07:00
2023-01-20 09:50:36 -08:00
ri . cw . p ( f " return { ret_ok } ; " )
ri . cw . nl ( )
if ' reply ' in ri . op [ ri . op_mode ] :
2023-06-01 19:35:45 -07:00
ri . cw . p ( ' err_free: ' )
2023-01-20 09:50:36 -08:00
ri . cw . p ( f " { call_free ( ri , rdir ( direction ) , ' rsp ' ) } " )
2023-06-01 19:35:45 -07:00
ri . cw . p ( f " return { ret_err } ; " )
2023-01-20 09:50:36 -08:00
ri . cw . block_end ( )
def print_dump ( ri ) :
direction = " request "
print_prototype ( ri , direction , terminate = False )
ri . cw . block_start ( )
local_vars = [ ' struct ynl_dump_state yds = {} ; ' ,
' struct nlmsghdr *nlh; ' ,
2023-06-01 19:35:45 -07:00
' int err; ' ]
2023-01-20 09:50:36 -08:00
2023-12-13 15:14:27 -08:00
if ri . fixed_hdr :
local_vars + = [ ' size_t hdr_len; ' ,
' void *hdr; ' ]
ri . cw . write_func_lvar ( local_vars )
2023-01-20 09:50:36 -08:00
2024-02-27 14:30:23 -08:00
ri . cw . p ( ' yds.yarg.ys = ys; ' )
ri . cw . p ( f " yds.yarg.rsp_policy = & { ri . struct [ ' reply ' ] . render_name } _nest; " )
ri . cw . p ( " yds.yarg.data = NULL; " )
2023-01-20 09:50:36 -08:00
ri . cw . p ( f " yds.alloc_sz = sizeof( { type_name ( ri , rdir ( direction ) ) } ); " )
ri . cw . p ( f " yds.cb = { op_prefix ( ri , ' reply ' , deref = True ) } _parse; " )
2023-06-01 19:35:45 -07:00
if ri . op . value is not None :
ri . cw . p ( f ' yds.rsp_cmd = { ri . op . enum_name } ; ' )
else :
ri . cw . p ( f ' yds.rsp_cmd = { ri . op . rsp_value } ; ' )
2023-01-20 09:50:36 -08:00
ri . cw . nl ( )
ri . cw . p ( f " nlh = ynl_gemsg_start_dump(ys, { ri . nl . get_family_id ( ) } , { ri . op . enum_name } , 1); " )
2023-12-13 15:14:27 -08:00
if ri . fixed_hdr :
ri . cw . p ( " hdr_len = sizeof(req->_hdr); " )
2024-02-27 14:30:21 -08:00
ri . cw . p ( " hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len); " )
2023-12-13 15:14:27 -08:00
ri . cw . p ( " memcpy(hdr, &req->_hdr, hdr_len); " )
ri . cw . nl ( )
2023-01-20 09:50:36 -08:00
if " request " in ri . op [ ri . op_mode ] :
ri . cw . p ( f " ys->req_policy = & { ri . struct [ ' request ' ] . render_name } _nest; " )
ri . cw . nl ( )
for _ , attr in ri . struct [ " request " ] . member_list ( ) :
attr . attr_put ( ri , " req " )
ri . cw . nl ( )
2023-06-01 19:35:45 -07:00
ri . cw . p ( ' err = ynl_exec_dump(ys, nlh, &yds); ' )
2023-01-20 09:50:36 -08:00
ri . cw . p ( ' if (err < 0) ' )
ri . cw . p ( ' goto free_list; ' )
ri . cw . nl ( )
ri . cw . p ( ' return yds.first; ' )
ri . cw . nl ( )
ri . cw . p ( ' free_list: ' )
ri . cw . p ( call_free ( ri , rdir ( direction ) , ' yds.first ' ) )
ri . cw . p ( ' return NULL; ' )
ri . cw . block_end ( )
def call_free ( ri , direction , var ) :
return f " { op_prefix ( ri , direction ) } _free( { var } ); "
def free_arg_name ( direction ) :
if direction :
return direction_to_suffix [ direction ] [ 1 : ]
return ' obj '
2023-06-01 19:35:46 -07:00
def print_alloc_wrapper ( ri , direction ) :
name = op_prefix ( ri , direction )
ri . cw . write_func_prot ( f ' static inline struct { name } * ' , f " { name } _alloc " , [ f " void " ] )
ri . cw . block_start ( )
ri . cw . p ( f ' return calloc(1, sizeof(struct { name } )); ' )
ri . cw . block_end ( )
2023-01-20 09:50:36 -08:00
def print_free_prototype ( ri , direction , suffix = ' ; ' ) :
name = op_prefix ( ri , direction )
2023-06-09 14:43:40 -07:00
struct_name = name
if ri . type_name_conflict :
struct_name + = ' _ '
2023-01-20 09:50:36 -08:00
arg = free_arg_name ( direction )
2023-06-09 14:43:40 -07:00
ri . cw . write_func_prot ( ' void ' , f " { name } _free " , [ f " struct { struct_name } * { arg } " ] , suffix = suffix )
2023-01-20 09:50:36 -08:00
def _print_type ( ri , direction , struct ) :
suffix = f ' _ { ri . type_name } { direction_to_suffix [ direction ] } '
2023-06-09 14:43:40 -07:00
if not direction and ri . type_name_conflict :
suffix + = ' _ '
2023-01-20 09:50:36 -08:00
if ri . op_mode == ' dump ' :
suffix + = ' _dump '
2023-11-22 19:08:44 -08:00
ri . cw . block_start ( line = f " struct { ri . family . c_name } { suffix } " )
2023-01-20 09:50:36 -08:00
2023-12-13 15:14:27 -08:00
if ri . fixed_hdr :
ri . cw . p ( ri . fixed_hdr + ' _hdr; ' )
ri . cw . nl ( )
2023-01-20 09:50:36 -08:00
meta_started = False
for _ , attr in struct . member_list ( ) :
for type_filter in [ ' len ' , ' bit ' ] :
line = attr . presence_member ( ri . ku_space , type_filter )
if line :
if not meta_started :
ri . cw . block_start ( line = f " struct " )
meta_started = True
ri . cw . p ( line )
if meta_started :
ri . cw . block_end ( line = ' _present; ' )
ri . cw . nl ( )
for arg in struct . inherited :
ri . cw . p ( f " __u32 { arg } ; " )
for _ , attr in struct . member_list ( ) :
attr . struct_member ( ri )
ri . cw . block_end ( line = ' ; ' )
ri . cw . nl ( )
def print_type ( ri , direction ) :
_print_type ( ri , direction , ri . struct [ direction ] )
def print_type_full ( ri , struct ) :
_print_type ( ri , " " , struct )
def print_type_helpers ( ri , direction , deref = False ) :
print_free_prototype ( ri , direction )
2023-06-01 19:35:46 -07:00
ri . cw . nl ( )
2023-01-20 09:50:36 -08:00
if ri . ku_space == ' user ' and direction == ' request ' :
for _ , attr in ri . struct [ direction ] . member_list ( ) :
attr . setter ( ri , ri . attr_set , direction , deref = deref )
ri . cw . nl ( )
def print_req_type_helpers ( ri ) :
2023-10-06 06:50:32 -07:00
if len ( ri . struct [ " request " ] . attr_list ) == 0 :
return
2023-06-01 19:35:46 -07:00
print_alloc_wrapper ( ri , " request " )
2023-01-20 09:50:36 -08:00
print_type_helpers ( ri , " request " )
def print_rsp_type_helpers ( ri ) :
if ' reply ' not in ri . op [ ri . op_mode ] :
return
print_type_helpers ( ri , " reply " )
def print_parse_prototype ( ri , direction , terminate = True ) :
suffix = " _rsp " if direction == " reply " else " _req "
term = ' ; ' if terminate else ' '
ri . cw . write_func_prot ( ' void ' , f " { ri . op . render_name } { suffix } _parse " ,
[ ' const struct nlattr **tb ' ,
f " struct { ri . op . render_name } { suffix } *req " ] ,
suffix = term )
def print_req_type ( ri ) :
2023-10-06 06:50:32 -07:00
if len ( ri . struct [ " request " ] . attr_list ) == 0 :
return
2023-01-20 09:50:36 -08:00
print_type ( ri , " request " )
2023-06-01 19:35:46 -07:00
def print_req_free ( ri ) :
if ' request ' not in ri . op [ ri . op_mode ] :
return
_free_type ( ri , ' request ' , ri . struct [ ' request ' ] )
2023-01-20 09:50:36 -08:00
def print_rsp_type ( ri ) :
if ( ri . op_mode == ' do ' or ri . op_mode == ' dump ' ) and ' reply ' in ri . op [ ri . op_mode ] :
direction = ' reply '
elif ri . op_mode == ' event ' :
direction = ' reply '
else :
return
print_type ( ri , direction )
def print_wrapped_type ( ri ) :
ri . cw . block_start ( line = f " { type_name ( ri , ' reply ' ) } " )
if ri . op_mode == ' dump ' :
ri . cw . p ( f " { type_name ( ri , ' reply ' ) } *next; " )
elif ri . op_mode == ' notify ' or ri . op_mode == ' event ' :
ri . cw . p ( ' __u16 family; ' )
ri . cw . p ( ' __u8 cmd; ' )
2023-06-01 19:35:48 -07:00
ri . cw . p ( ' struct ynl_ntf_base_type *next; ' )
2023-01-20 09:50:36 -08:00
ri . cw . p ( f " void (*free)( { type_name ( ri , ' reply ' ) } *ntf); " )
2023-10-20 15:18:27 -07:00
ri . cw . p ( f " { type_name ( ri , ' reply ' , deref = True ) } obj __attribute__((aligned(8))); " )
2023-01-20 09:50:36 -08:00
ri . cw . block_end ( line = ' ; ' )
ri . cw . nl ( )
print_free_prototype ( ri , ' reply ' )
ri . cw . nl ( )
def _free_type_members_iter ( ri , struct ) :
for _ , attr in struct . member_list ( ) :
if attr . free_needs_iter ( ) :
ri . cw . p ( ' unsigned int i; ' )
ri . cw . nl ( )
break
def _free_type_members ( ri , var , struct , ref = ' ' ) :
for _ , attr in struct . member_list ( ) :
attr . free ( ri , var , ref )
def _free_type ( ri , direction , struct ) :
var = free_arg_name ( direction )
print_free_prototype ( ri , direction , suffix = ' ' )
ri . cw . block_start ( )
_free_type_members_iter ( ri , struct )
_free_type_members ( ri , var , struct )
if direction :
ri . cw . p ( f ' free( { var } ); ' )
ri . cw . block_end ( )
ri . cw . nl ( )
2023-12-13 15:14:32 -08:00
def free_rsp_nested_prototype ( ri ) :
print_free_prototype ( ri , " " )
2023-01-20 09:50:36 -08:00
def free_rsp_nested ( ri , struct ) :
_free_type ( ri , " " , struct )
def print_rsp_free ( ri ) :
if ' reply ' not in ri . op [ ri . op_mode ] :
return
_free_type ( ri , ' reply ' , ri . struct [ ' reply ' ] )
def print_dump_type_free ( ri ) :
sub_type = type_name ( ri , ' reply ' )
print_free_prototype ( ri , ' reply ' , suffix = ' ' )
ri . cw . block_start ( )
ri . cw . p ( f " { sub_type } *next = rsp; " )
ri . cw . nl ( )
2023-06-01 19:35:45 -07:00
ri . cw . block_start ( line = ' while ((void *)next != YNL_LIST_END) ' )
2023-01-20 09:50:36 -08:00
_free_type_members_iter ( ri , ri . struct [ ' reply ' ] )
ri . cw . p ( ' rsp = next; ' )
ri . cw . p ( ' next = rsp->next; ' )
ri . cw . nl ( )
_free_type_members ( ri , ' rsp ' , ri . struct [ ' reply ' ] , ref = ' obj. ' )
ri . cw . p ( f ' free(rsp); ' )
ri . cw . block_end ( )
ri . cw . block_end ( )
ri . cw . nl ( )
def print_ntf_type_free ( ri ) :
print_free_prototype ( ri , ' reply ' , suffix = ' ' )
ri . cw . block_start ( )
_free_type_members_iter ( ri , ri . struct [ ' reply ' ] )
_free_type_members ( ri , ' rsp ' , ri . struct [ ' reply ' ] , ref = ' obj. ' )
ri . cw . p ( f ' free(rsp); ' )
ri . cw . block_end ( )
ri . cw . nl ( )
def print_req_policy_fwd ( cw , struct , ri = None , terminate = True ) :
2023-08-03 13:13:32 +02:00
if terminate and ri and policy_should_be_static ( struct . family ) :
2023-01-20 09:50:36 -08:00
return
if terminate :
prefix = ' extern '
else :
2023-08-03 13:13:32 +02:00
if ri and policy_should_be_static ( struct . family ) :
2023-01-20 09:50:36 -08:00
prefix = ' static '
else :
prefix = ' '
suffix = ' ; ' if terminate else ' = { '
max_attr = struct . attr_max_val
if ri :
name = ri . op . render_name
if ri . op . dual_policy :
name + = ' _ ' + ri . op_mode
else :
name = struct . render_name
cw . p ( f " { prefix } const struct nla_policy { name } _nl_policy[ { max_attr . enum_name } + 1] { suffix } " )
def print_req_policy ( cw , struct , ri = None ) :
2023-10-25 09:22:53 -07:00
if ri and ri . op :
cw . ifdef_block ( ri . op . get ( ' config-cond ' , None ) )
2023-01-20 09:50:36 -08:00
print_req_policy_fwd ( cw , struct , ri = ri , terminate = False )
for _ , arg in struct . member_list ( ) :
arg . attr_policy ( cw )
cw . p ( " }; " )
2023-10-25 09:22:53 -07:00
cw . ifdef_block ( None )
2023-08-08 13:09:07 -07:00
cw . nl ( )
2023-01-20 09:50:36 -08:00
def kernel_can_gen_family_struct ( family ) :
return family . proto == ' genetlink '
2023-08-03 13:13:32 +02:00
def policy_should_be_static ( family ) :
return family . kernel_policy == ' split ' or kernel_can_gen_family_struct ( family )
2023-10-18 09:39:16 -07:00
def print_kernel_policy_ranges ( family , cw ) :
first = True
for _ , attr_set in family . attr_sets . items ( ) :
if attr_set . subset_of :
continue
for _ , attr in attr_set . items ( ) :
if not attr . request :
continue
if ' full-range ' not in attr . checks :
continue
if first :
cw . p ( ' /* Integer value ranges */ ' )
first = False
sign = ' ' if attr . type [ 0 ] == ' u ' else ' _signed '
2023-11-22 09:33:23 -08:00
suffix = ' ULL ' if attr . type [ 0 ] == ' u ' else ' LL '
2023-10-25 09:22:04 -07:00
cw . block_start ( line = f ' static const struct netlink_range_validation { sign } { c_lower ( attr . enum_name ) } _range = ' )
2023-10-18 09:39:16 -07:00
members = [ ]
if ' min ' in attr . checks :
2023-11-22 09:33:23 -08:00
members . append ( ( ' min ' , str ( attr . get_limit ( ' min ' ) ) + suffix ) )
2023-10-18 09:39:16 -07:00
if ' max ' in attr . checks :
2023-11-22 09:33:23 -08:00
members . append ( ( ' max ' , str ( attr . get_limit ( ' max ' ) ) + suffix ) )
2023-10-18 09:39:16 -07:00
cw . write_struct_init ( members )
cw . block_end ( line = ' ; ' )
cw . nl ( )
2023-01-20 09:50:36 -08:00
def print_kernel_op_table_fwd ( family , cw , terminate ) :
exported = not kernel_can_gen_family_struct ( family )
if not terminate or exported :
cw . p ( f " /* Ops table for { family . name } */ " )
pol_to_struct = { ' global ' : ' genl_small_ops ' ,
' per-op ' : ' genl_ops ' ,
' split ' : ' genl_split_ops ' }
struct_type = pol_to_struct [ family . kernel_policy ]
2023-03-20 21:41:59 -07:00
if not exported :
cnt = " "
elif family . kernel_policy == ' split ' :
2023-01-20 09:50:36 -08:00
cnt = 0
for op in family . ops . values ( ) :
if ' do ' in op :
cnt + = 1
if ' dump ' in op :
cnt + = 1
else :
cnt = len ( family . ops )
qual = ' static const ' if not exported else ' const '
2023-11-22 19:08:44 -08:00
line = f " { qual } struct { struct_type } { family . c_name } _nl_ops[ { cnt } ] "
2023-01-20 09:50:36 -08:00
if terminate :
cw . p ( f " extern { line } ; " )
else :
cw . block_start ( line = line + ' = ' )
if not terminate :
return
cw . nl ( )
for name in family . hooks [ ' pre ' ] [ ' do ' ] [ ' list ' ] :
cw . write_func_prot ( ' int ' , c_lower ( name ) ,
[ ' const struct genl_split_ops *ops ' ,
' struct sk_buff *skb ' , ' struct genl_info *info ' ] , suffix = ' ; ' )
for name in family . hooks [ ' post ' ] [ ' do ' ] [ ' list ' ] :
cw . write_func_prot ( ' void ' , c_lower ( name ) ,
[ ' const struct genl_split_ops *ops ' ,
' struct sk_buff *skb ' , ' struct genl_info *info ' ] , suffix = ' ; ' )
for name in family . hooks [ ' pre ' ] [ ' dump ' ] [ ' list ' ] :
cw . write_func_prot ( ' int ' , c_lower ( name ) ,
[ ' struct netlink_callback *cb ' ] , suffix = ' ; ' )
for name in family . hooks [ ' post ' ] [ ' dump ' ] [ ' list ' ] :
cw . write_func_prot ( ' int ' , c_lower ( name ) ,
[ ' struct netlink_callback *cb ' ] , suffix = ' ; ' )
cw . nl ( )
for op_name , op in family . ops . items ( ) :
if op . is_async :
continue
if ' do ' in op :
name = c_lower ( f " { family . name } -nl- { op_name } -doit " )
cw . write_func_prot ( ' int ' , name ,
[ ' struct sk_buff *skb ' , ' struct genl_info *info ' ] , suffix = ' ; ' )
if ' dump ' in op :
name = c_lower ( f " { family . name } -nl- { op_name } -dumpit " )
cw . write_func_prot ( ' int ' , name ,
[ ' struct sk_buff *skb ' , ' struct netlink_callback *cb ' ] , suffix = ' ; ' )
cw . nl ( )
def print_kernel_op_table_hdr ( family , cw ) :
print_kernel_op_table_fwd ( family , cw , terminate = True )
def print_kernel_op_table ( family , cw ) :
print_kernel_op_table_fwd ( family , cw , terminate = False )
if family . kernel_policy == ' global ' or family . kernel_policy == ' per-op ' :
for op_name , op in family . ops . items ( ) :
if op . is_async :
continue
2023-10-25 09:22:53 -07:00
cw . ifdef_block ( op . get ( ' config-cond ' , None ) )
2023-01-20 09:50:36 -08:00
cw . block_start ( )
members = [ ( ' cmd ' , op . enum_name ) ]
if ' dont-validate ' in op :
members . append ( ( ' validate ' ,
' | ' . join ( [ c_upper ( ' genl-dont-validate- ' + x )
for x in op [ ' dont-validate ' ] ] ) ) , )
for op_mode in [ ' do ' , ' dump ' ] :
if op_mode in op :
name = c_lower ( f " { family . name } -nl- { op_name } - { op_mode } it " )
members . append ( ( op_mode + ' it ' , name ) )
if family . kernel_policy == ' per-op ' :
struct = Struct ( family , op [ ' attribute-set ' ] ,
type_list = op [ ' do ' ] [ ' request ' ] [ ' attributes ' ] )
name = c_lower ( f " { family . name } - { op_name } -nl-policy " )
members . append ( ( ' policy ' , name ) )
members . append ( ( ' maxattr ' , struct . attr_max_val . enum_name ) )
if ' flags ' in op :
members . append ( ( ' flags ' , ' | ' . join ( [ c_upper ( ' genl- ' + x ) for x in op [ ' flags ' ] ] ) ) )
cw . write_struct_init ( members )
cw . block_end ( line = ' , ' )
elif family . kernel_policy == ' split ' :
cb_names = { ' do ' : { ' pre ' : ' pre_doit ' , ' post ' : ' post_doit ' } ,
' dump ' : { ' pre ' : ' start ' , ' post ' : ' done ' } }
for op_name , op in family . ops . items ( ) :
for op_mode in [ ' do ' , ' dump ' ] :
if op . is_async or op_mode not in op :
continue
2023-10-25 09:22:53 -07:00
cw . ifdef_block ( op . get ( ' config-cond ' , None ) )
2023-01-20 09:50:36 -08:00
cw . block_start ( )
members = [ ( ' cmd ' , op . enum_name ) ]
if ' dont-validate ' in op :
2023-08-03 13:13:30 +02:00
dont_validate = [ ]
for x in op [ ' dont-validate ' ] :
if op_mode == ' do ' and x in [ ' dump ' , ' dump-strict ' ] :
continue
if op_mode == " dump " and x == ' strict ' :
continue
dont_validate . append ( x )
2023-08-08 11:03:44 +02:00
if dont_validate :
members . append ( ( ' validate ' ,
' | ' . join ( [ c_upper ( ' genl-dont-validate- ' + x )
for x in dont_validate ] ) ) , )
2023-01-20 09:50:36 -08:00
name = c_lower ( f " { family . name } -nl- { op_name } - { op_mode } it " )
if ' pre ' in op [ op_mode ] :
members . append ( ( cb_names [ op_mode ] [ ' pre ' ] , c_lower ( op [ op_mode ] [ ' pre ' ] ) ) )
members . append ( ( op_mode + ' it ' , name ) )
if ' post ' in op [ op_mode ] :
members . append ( ( cb_names [ op_mode ] [ ' post ' ] , c_lower ( op [ op_mode ] [ ' post ' ] ) ) )
if ' request ' in op [ op_mode ] :
struct = Struct ( family , op [ ' attribute-set ' ] ,
type_list = op [ op_mode ] [ ' request ' ] [ ' attributes ' ] )
if op . dual_policy :
name = c_lower ( f " { family . name } - { op_name } - { op_mode } -nl-policy " )
else :
name = c_lower ( f " { family . name } - { op_name } -nl-policy " )
members . append ( ( ' policy ' , name ) )
members . append ( ( ' maxattr ' , struct . attr_max_val . enum_name ) )
flags = ( op [ ' flags ' ] if ' flags ' in op else [ ] ) + [ ' cmd-cap- ' + op_mode ]
members . append ( ( ' flags ' , ' | ' . join ( [ c_upper ( ' genl- ' + x ) for x in flags ] ) ) )
cw . write_struct_init ( members )
cw . block_end ( line = ' , ' )
2023-10-25 09:22:53 -07:00
cw . ifdef_block ( None )
2023-01-20 09:50:36 -08:00
cw . block_end ( line = ' ; ' )
cw . nl ( )
def print_kernel_mcgrp_hdr ( family , cw ) :
if not family . mcgrps [ ' list ' ] :
return
cw . block_start ( ' enum ' )
for grp in family . mcgrps [ ' list ' ] :
grp_id = c_upper ( f " { family . name } -nlgrp- { grp [ ' name ' ] } , " )
cw . p ( grp_id )
cw . block_end ( ' ; ' )
cw . nl ( )
def print_kernel_mcgrp_src ( family , cw ) :
if not family . mcgrps [ ' list ' ] :
return
2023-11-22 19:08:44 -08:00
cw . block_start ( ' static const struct genl_multicast_group ' + family . c_name + ' _nl_mcgrps[] = ' )
2023-01-20 09:50:36 -08:00
for grp in family . mcgrps [ ' list ' ] :
name = grp [ ' name ' ]
grp_id = c_upper ( f " { family . name } -nlgrp- { name } " )
cw . p ( ' [ ' + grp_id + ' ] = { " ' + name + ' " , }, ' )
cw . block_end ( ' ; ' )
cw . nl ( )
def print_kernel_family_struct_hdr ( family , cw ) :
if not kernel_can_gen_family_struct ( family ) :
return
2023-11-22 19:08:44 -08:00
cw . p ( f " extern struct genl_family { family . c_name } _nl_family; " )
2023-01-20 09:50:36 -08:00
cw . nl ( )
def print_kernel_family_struct_src ( family , cw ) :
if not kernel_can_gen_family_struct ( family ) :
return
cw . block_start ( f " struct genl_family { family . name } _nl_family __ro_after_init = " )
cw . p ( ' .name \t \t = ' + family . fam_key + ' , ' )
cw . p ( ' .version \t = ' + family . ver_key + ' , ' )
cw . p ( ' .netnsok \t = true, ' )
cw . p ( ' .parallel_ops \t = true, ' )
cw . p ( ' .module \t \t = THIS_MODULE, ' )
if family . kernel_policy == ' per-op ' :
2023-11-22 19:08:44 -08:00
cw . p ( f ' .ops \t \t = { family . c_name } _nl_ops, ' )
cw . p ( f ' .n_ops \t \t = ARRAY_SIZE( { family . c_name } _nl_ops), ' )
2023-01-20 09:50:36 -08:00
elif family . kernel_policy == ' split ' :
2023-11-22 19:08:44 -08:00
cw . p ( f ' .split_ops \t = { family . c_name } _nl_ops, ' )
cw . p ( f ' .n_split_ops \t = ARRAY_SIZE( { family . c_name } _nl_ops), ' )
2023-01-20 09:50:36 -08:00
if family . mcgrps [ ' list ' ] :
2023-11-22 19:08:44 -08:00
cw . p ( f ' .mcgrps \t \t = { family . c_name } _nl_mcgrps, ' )
cw . p ( f ' .n_mcgrps \t = ARRAY_SIZE( { family . c_name } _nl_mcgrps), ' )
2023-01-20 09:50:36 -08:00
cw . block_end ( ' ; ' )
def uapi_enum_start ( family , cw , obj , ckey = ' ' , enum_name = ' enum-name ' ) :
start_line = ' enum '
if enum_name in obj :
if obj [ enum_name ] :
start_line = ' enum ' + c_lower ( obj [ enum_name ] )
elif ckey and ckey in obj :
2023-11-22 19:08:44 -08:00
start_line = ' enum ' + family . c_name + ' _ ' + c_lower ( obj [ ckey ] )
2023-01-20 09:50:36 -08:00
cw . block_start ( line = start_line )
def render_uapi ( family , cw ) :
2023-10-03 15:57:35 -07:00
hdr_prot = f " _UAPI_LINUX_ { c_upper ( family . uapi_header_name ) } _H "
2023-01-20 09:50:36 -08:00
cw . p ( ' #ifndef ' + hdr_prot )
cw . p ( ' #define ' + hdr_prot )
cw . nl ( )
defines = [ ( family . fam_key , family [ " name " ] ) ,
( family . ver_key , family . get ( ' version ' , 1 ) ) ]
cw . writes_defines ( defines )
cw . nl ( )
defines = [ ]
for const in family [ ' definitions ' ] :
if const [ ' type ' ] != ' const ' :
cw . writes_defines ( defines )
defines = [ ]
cw . nl ( )
2023-01-25 16:02:33 -08:00
# Write kdoc for enum and flags (one day maybe also structs)
if const [ ' type ' ] == ' enum ' or const [ ' type ' ] == ' flags ' :
2023-01-20 09:50:36 -08:00
enum = family . consts [ const [ ' name ' ] ]
if enum . has_doc ( ) :
cw . p ( ' /** ' )
doc = ' '
if ' doc ' in enum :
doc = ' - ' + enum [ ' doc ' ]
cw . write_doc_line ( enum . enum_name + doc )
2023-03-07 16:39:22 -08:00
for entry in enum . entries . values ( ) :
2023-01-20 09:50:36 -08:00
if entry . has_doc ( ) :
doc = ' @ ' + entry . c_name + ' : ' + entry [ ' doc ' ]
cw . write_doc_line ( doc )
cw . p ( ' */ ' )
uapi_enum_start ( family , cw , const , ' name ' )
name_pfx = const . get ( ' name-prefix ' , f " { family . name } - { const [ ' name ' ] } - " )
2023-03-07 16:39:22 -08:00
for entry in enum . entries . values ( ) :
2023-01-20 09:50:36 -08:00
suffix = ' , '
2023-01-25 16:02:33 -08:00
if entry . value_change :
suffix = f " = { entry . user_value ( ) } " + suffix
2023-01-20 09:50:36 -08:00
cw . p ( entry . c_name + suffix )
if const . get ( ' render-max ' , False ) :
cw . nl ( )
2023-07-27 09:29:59 -07:00
cw . p ( ' /* private: */ ' )
2023-03-09 13:25:25 +01:00
if const [ ' type ' ] == ' flags ' :
max_name = c_upper ( name_pfx + ' mask ' )
max_val = f ' = { enum . get_mask ( ) } , '
cw . p ( max_name + max_val )
else :
max_name = c_upper ( name_pfx + ' max ' )
cw . p ( ' __ ' + max_name + ' , ' )
cw . p ( max_name + ' = (__ ' + max_name + ' - 1) ' )
2023-01-20 09:50:36 -08:00
cw . block_end ( line = ' ; ' )
cw . nl ( )
elif const [ ' type ' ] == ' const ' :
defines . append ( [ c_upper ( family . get ( ' c-define-name ' ,
f " { family . name } - { const [ ' name ' ] } " ) ) ,
const [ ' value ' ] ] )
if defines :
cw . writes_defines ( defines )
cw . nl ( )
max_by_define = family . get ( ' max-by-define ' , False )
2023-01-30 18:33:44 -08:00
for _ , attr_set in family . attr_sets . items ( ) :
2023-01-20 09:50:36 -08:00
if attr_set . subset_of :
continue
2023-10-25 11:27:39 -07:00
max_value = f " ( { attr_set . cnt_name } - 1) "
2023-01-20 09:50:36 -08:00
val = 0
uapi_enum_start ( family , cw , attr_set . yaml , ' enum-name ' )
for _ , attr in attr_set . items ( ) :
suffix = ' , '
2023-01-30 18:33:44 -08:00
if attr . value != val :
suffix = f " = { attr . value } , "
val = attr . value
2023-01-20 09:50:36 -08:00
val + = 1
cw . p ( attr . enum_name + suffix )
cw . nl ( )
2023-10-25 11:27:39 -07:00
cw . p ( attr_set . cnt_name + ( ' ' if max_by_define else ' , ' ) )
2023-01-20 09:50:36 -08:00
if not max_by_define :
cw . p ( f " { attr_set . max_name } = { max_value } " )
cw . block_end ( line = ' ; ' )
if max_by_define :
cw . p ( f " #define { attr_set . max_name } { max_value } " )
cw . nl ( )
# Commands
separate_ntf = ' async-prefix ' in family [ ' operations ' ]
max_name = c_upper ( family . get ( ' cmd-max-name ' , f " { family . op_prefix } MAX " ) )
cnt_name = c_upper ( family . get ( ' cmd-cnt-name ' , f " __ { family . op_prefix } MAX " ) )
max_value = f " ( { cnt_name } - 1) "
uapi_enum_start ( family , cw , family [ ' operations ' ] , ' enum-name ' )
2023-03-01 10:36:41 -08:00
val = 0
2023-01-30 18:33:44 -08:00
for op in family . msgs . values ( ) :
2023-01-20 09:50:36 -08:00
if separate_ntf and ( ' notify ' in op or ' event ' in op ) :
continue
suffix = ' , '
2023-03-01 10:36:41 -08:00
if op . value != val :
suffix = f " = { op . value } , "
val = op . value
2023-01-20 09:50:36 -08:00
cw . p ( op . enum_name + suffix )
2023-03-01 10:36:41 -08:00
val + = 1
2023-01-20 09:50:36 -08:00
cw . nl ( )
cw . p ( cnt_name + ( ' ' if max_by_define else ' , ' ) )
if not max_by_define :
cw . p ( f " { max_name } = { max_value } " )
cw . block_end ( line = ' ; ' )
if max_by_define :
cw . p ( f " #define { max_name } { max_value } " )
cw . nl ( )
if separate_ntf :
uapi_enum_start ( family , cw , family [ ' operations ' ] , enum_name = ' async-enum ' )
2023-01-30 18:33:44 -08:00
for op in family . msgs . values ( ) :
2023-01-20 09:50:36 -08:00
if separate_ntf and not ( ' notify ' in op or ' event ' in op ) :
continue
suffix = ' , '
if ' value ' in op :
suffix = f " = { op [ ' value ' ] } , "
cw . p ( op . enum_name + suffix )
cw . block_end ( line = ' ; ' )
cw . nl ( )
# Multicast
defines = [ ]
for grp in family . mcgrps [ ' list ' ] :
name = grp [ ' name ' ]
defines . append ( [ c_upper ( grp . get ( ' c-define-name ' , f " { family . name } -mcgrp- { name } " ) ) ,
f ' { name } ' ] )
cw . nl ( )
if defines :
cw . writes_defines ( defines )
cw . nl ( )
cw . p ( f ' #endif /* { hdr_prot } */ ' )
2023-06-01 19:35:48 -07:00
def _render_user_ntf_entry ( ri , op ) :
ri . cw . block_start ( line = f " [ { op . enum_name } ] = " )
ri . cw . p ( f " .alloc_sz \t = sizeof( { type_name ( ri , ' event ' ) } ), " )
ri . cw . p ( f " .cb \t \t = { op_prefix ( ri , ' reply ' , deref = True ) } _parse, " )
ri . cw . p ( f " .policy \t \t = & { ri . struct [ ' reply ' ] . render_name } _nest, " )
ri . cw . p ( f " .free \t \t = (void *) { op_prefix ( ri , ' notify ' ) } _free, " )
ri . cw . block_end ( line = ' , ' )
2023-06-01 19:35:47 -07:00
def render_user_family ( family , cw , prototype ) :
symbol = f ' const struct ynl_family ynl_ { family . c_name } _family '
if prototype :
cw . p ( f ' extern { symbol } ; ' )
2023-06-01 19:35:48 -07:00
return
2023-06-08 14:11:57 -07:00
if family . ntfs :
2023-06-01 19:35:48 -07:00
cw . block_start ( line = f " static const struct ynl_ntf_info { family [ ' name ' ] } _ntf_info[] = " )
2023-06-08 14:11:57 -07:00
for ntf_op_name , ntf_op in family . ntfs . items ( ) :
2023-06-08 14:11:58 -07:00
if ' notify ' in ntf_op :
op = family . ops [ ntf_op [ ' notify ' ] ]
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , family , " user " , op , " notify " )
2023-06-08 14:11:58 -07:00
elif ' event ' in ntf_op :
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , family , " user " , ntf_op , " event " )
2023-06-08 14:11:58 -07:00
else :
raise Exception ( ' Invalid notification ' + ntf_op_name )
2023-06-08 14:11:57 -07:00
_render_user_ntf_entry ( ri , ntf_op )
2023-06-01 19:35:48 -07:00
for op_name , op in family . ops . items ( ) :
if ' event ' not in op :
continue
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , family , " user " , op , " event " )
2023-06-01 19:35:48 -07:00
_render_user_ntf_entry ( ri , op )
cw . block_end ( line = " ; " )
cw . nl ( )
cw . block_start ( f ' { symbol } = ' )
2023-11-22 19:08:44 -08:00
cw . p ( f ' .name \t \t = " { family . c_name } " , ' )
2023-12-13 15:14:27 -08:00
if family . fixed_header :
cw . p ( f ' .hdr_len \t = sizeof(struct genlmsghdr) + sizeof(struct { c_lower ( family . fixed_header ) } ), ' )
else :
cw . p ( ' .hdr_len \t = sizeof(struct genlmsghdr), ' )
2023-06-08 14:11:57 -07:00
if family . ntfs :
2023-06-01 19:35:48 -07:00
cw . p ( f " .ntf_info \t = { family [ ' name ' ] } _ntf_info, " )
2024-02-27 14:30:22 -08:00
cw . p ( f " .ntf_info_size \t = YNL_ARRAY_SIZE( { family [ ' name ' ] } _ntf_info), " )
2023-06-01 19:35:48 -07:00
cw . block_end ( line = ' ; ' )
2023-06-01 19:35:47 -07:00
2023-10-21 13:27:03 +02:00
def family_contains_bitfield32 ( family ) :
for _ , attr_set in family . attr_sets . items ( ) :
if attr_set . subset_of :
continue
for _ , attr in attr_set . items ( ) :
if attr . type == " bitfield32 " :
return True
return False
2023-01-20 09:50:36 -08:00
def find_kernel_root ( full_path ) :
sub_path = ' '
while True :
sub_path = os . path . join ( os . path . basename ( full_path ) , sub_path )
full_path = os . path . dirname ( full_path )
maintainers = os . path . join ( full_path , " MAINTAINERS " )
if os . path . exists ( maintainers ) :
return full_path , sub_path [ : - 1 ]
def main ( ) :
parser = argparse . ArgumentParser ( description = ' Netlink simple parsing generator ' )
parser . add_argument ( ' --mode ' , dest = ' mode ' , type = str , required = True )
parser . add_argument ( ' --spec ' , dest = ' spec ' , type = str , required = True )
parser . add_argument ( ' --header ' , dest = ' header ' , action = ' store_true ' , default = None )
parser . add_argument ( ' --source ' , dest = ' header ' , action = ' store_false ' )
parser . add_argument ( ' --user-header ' , nargs = ' + ' , default = [ ] )
2023-11-29 11:36:22 -08:00
parser . add_argument ( ' --cmp-out ' , action = ' store_true ' , default = None ,
help = ' Do not overwrite the output file if the new output is identical to the old ' )
2023-06-09 14:43:35 -07:00
parser . add_argument ( ' --exclude-op ' , action = ' append ' , default = [ ] )
2023-08-24 14:24:31 -07:00
parser . add_argument ( ' -o ' , dest = ' out_file ' , type = str , default = None )
2023-01-20 09:50:36 -08:00
args = parser . parse_args ( )
if args . header is None :
parser . error ( " --header or --source is required " )
2023-06-09 14:43:35 -07:00
exclude_ops = [ re . compile ( expr ) for expr in args . exclude_op ]
2023-01-20 09:50:36 -08:00
try :
2023-06-09 14:43:35 -07:00
parsed = Family ( args . spec , exclude_ops )
2023-03-15 16:03:51 -07:00
if parsed . license != ' ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) ' :
print ( ' Spec license: ' , parsed . license )
print ( ' License must be: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) ' )
os . sys . exit ( 1 )
2023-01-20 09:50:36 -08:00
except yaml . YAMLError as exc :
print ( exc )
os . sys . exit ( 1 )
return
2023-06-07 13:23:56 -07:00
supported_models = [ ' unified ' ]
2023-08-03 13:13:31 +02:00
if args . mode in [ ' user ' , ' kernel ' ] :
2023-06-07 13:23:56 -07:00
supported_models + = [ ' directional ' ]
if parsed . msg_id_model not in supported_models :
print ( f ' Message enum-model { parsed . msg_id_model } not supported for { args . mode } generation ' )
os . sys . exit ( 1 )
2023-11-29 11:36:22 -08:00
cw = CodeWriter ( BaseNlLib ( ) , args . out_file , overwrite = ( not args . cmp_out ) )
2023-01-20 09:50:36 -08:00
_ , spec_kernel = find_kernel_root ( args . spec )
2023-03-15 16:03:51 -07:00
if args . mode == ' uapi ' or args . header :
cw . p ( f ' /* SPDX-License-Identifier: { parsed . license } */ ' )
2023-01-20 09:50:36 -08:00
else :
2023-03-15 16:03:51 -07:00
cw . p ( f ' // SPDX-License-Identifier: { parsed . license } ' )
2023-01-20 09:50:36 -08:00
cw . p ( " /* Do not edit directly, auto-generated from: */ " )
cw . p ( f " /* \t { spec_kernel } */ " )
cw . p ( f " /* YNL-GEN { args . mode } { ' header ' if args . header else ' source ' } */ " )
2023-06-09 14:43:36 -07:00
if args . exclude_op or args . user_header :
line = ' '
line + = ' --user-header ' . join ( [ ' ' ] + args . user_header )
line + = ' --exclude-op ' . join ( [ ' ' ] + args . exclude_op )
cw . p ( f ' /* YNL-ARG { line } */ ' )
2023-01-20 09:50:36 -08:00
cw . nl ( )
if args . mode == ' uapi ' :
render_uapi ( parsed , cw )
return
2023-11-22 19:08:44 -08:00
hdr_prot = f " _LINUX_ { parsed . c_name . upper ( ) } _GEN_H "
2023-01-20 09:50:36 -08:00
if args . header :
cw . p ( ' #ifndef ' + hdr_prot )
cw . p ( ' #define ' + hdr_prot )
cw . nl ( )
if args . mode == ' kernel ' :
cw . p ( ' #include <net/netlink.h> ' )
cw . p ( ' #include <net/genetlink.h> ' )
cw . nl ( )
if not args . header :
if args . out_file :
cw . p ( f ' #include " { os . path . basename ( args . out_file [ : - 2 ] ) } .h " ' )
cw . nl ( )
2023-05-24 10:09:01 -07:00
headers = [ ' uapi/ ' + parsed . uapi_header ]
else :
2023-06-01 19:35:39 -07:00
cw . p ( ' #include <stdlib.h> ' )
2023-06-08 14:11:49 -07:00
cw . p ( ' #include <string.h> ' )
2023-06-01 19:35:39 -07:00
if args . header :
cw . p ( ' #include <linux/types.h> ' )
2023-10-21 13:27:03 +02:00
if family_contains_bitfield32 ( parsed ) :
cw . p ( ' #include <linux/netlink.h> ' )
2023-06-01 19:35:39 -07:00
else :
cw . p ( f ' #include " { parsed . name } -user.h " ' )
cw . p ( ' #include " ynl.h " ' )
2023-05-24 10:09:01 -07:00
headers = [ parsed . uapi_header ]
2023-01-20 09:50:36 -08:00
for definition in parsed [ ' definitions ' ] :
if ' header ' in definition :
headers . append ( definition [ ' header ' ] )
for one in headers :
cw . p ( f " #include < { one } > " )
cw . nl ( )
if args . mode == " user " :
if not args . header :
cw . p ( " #include <linux/genetlink.h> " )
cw . nl ( )
for one in args . user_header :
cw . p ( f ' #include " { one } " ' )
else :
cw . p ( ' struct ynl_sock; ' )
2023-06-01 19:35:47 -07:00
cw . nl ( )
render_user_family ( parsed , cw , True )
2023-01-20 09:50:36 -08:00
cw . nl ( )
if args . mode == " kernel " :
if args . header :
for _ , struct in sorted ( parsed . pure_nested_structs . items ( ) ) :
if struct . request :
cw . p ( ' /* Common nested types */ ' )
break
for attr_set , struct in sorted ( parsed . pure_nested_structs . items ( ) ) :
if struct . request :
print_req_policy_fwd ( cw , struct )
cw . nl ( )
if parsed . kernel_policy == ' global ' :
cw . p ( f " /* Global operation policy for { parsed . name } */ " )
struct = Struct ( parsed , parsed . global_policy_set , type_list = parsed . global_policy )
print_req_policy_fwd ( cw , struct )
cw . nl ( )
if parsed . kernel_policy in { ' per-op ' , ' split ' } :
for op_name , op in parsed . ops . items ( ) :
if ' do ' in op and ' event ' not in op :
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , op , " do " )
2023-01-20 09:50:36 -08:00
print_req_policy_fwd ( cw , ri . struct [ ' request ' ] , ri = ri )
cw . nl ( )
print_kernel_op_table_hdr ( parsed , cw )
print_kernel_mcgrp_hdr ( parsed , cw )
print_kernel_family_struct_hdr ( parsed , cw )
else :
2023-10-18 09:39:16 -07:00
print_kernel_policy_ranges ( parsed , cw )
2023-01-20 09:50:36 -08:00
for _ , struct in sorted ( parsed . pure_nested_structs . items ( ) ) :
if struct . request :
cw . p ( ' /* Common nested types */ ' )
break
for attr_set , struct in sorted ( parsed . pure_nested_structs . items ( ) ) :
if struct . request :
print_req_policy ( cw , struct )
cw . nl ( )
if parsed . kernel_policy == ' global ' :
cw . p ( f " /* Global operation policy for { parsed . name } */ " )
struct = Struct ( parsed , parsed . global_policy_set , type_list = parsed . global_policy )
print_req_policy ( cw , struct )
cw . nl ( )
for op_name , op in parsed . ops . items ( ) :
if parsed . kernel_policy in { ' per-op ' , ' split ' } :
2023-01-30 18:33:41 -08:00
for op_mode in [ ' do ' , ' dump ' ] :
2023-01-20 09:50:36 -08:00
if op_mode in op and ' request ' in op [ op_mode ] :
cw . p ( f " /* { op . enum_name } - { op_mode } */ " )
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , op , op_mode )
2023-01-20 09:50:36 -08:00
print_req_policy ( cw , ri . struct [ ' request ' ] , ri = ri )
cw . nl ( )
print_kernel_op_table ( parsed , cw )
print_kernel_mcgrp_src ( parsed , cw )
print_kernel_family_struct_src ( parsed , cw )
if args . mode == " user " :
if args . header :
2023-06-01 19:35:44 -07:00
cw . p ( ' /* Enums */ ' )
put_op_name_fwd ( parsed , cw )
for name , const in parsed . consts . items ( ) :
if isinstance ( const , EnumSet ) :
put_enum_to_str_fwd ( parsed , cw , const )
cw . nl ( )
2023-01-20 09:50:36 -08:00
cw . p ( ' /* Common nested types */ ' )
2023-06-07 13:23:57 -07:00
for attr_set , struct in parsed . pure_nested_structs . items ( ) :
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , " " , " " , attr_set )
2023-01-20 09:50:36 -08:00
print_type_full ( ri , struct )
for op_name , op in parsed . ops . items ( ) :
cw . p ( f " /* ============== { op . enum_name } ============== */ " )
if ' do ' in op and ' event ' not in op :
cw . p ( f " /* { op . enum_name } - do */ " )
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , op , " do " )
2023-01-20 09:50:36 -08:00
print_req_type ( ri )
print_req_type_helpers ( ri )
cw . nl ( )
print_rsp_type ( ri )
print_rsp_type_helpers ( ri )
cw . nl ( )
print_req_prototype ( ri )
cw . nl ( )
if ' dump ' in op :
cw . p ( f " /* { op . enum_name } - dump */ " )
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , op , ' dump ' )
2023-10-06 06:50:32 -07:00
print_req_type ( ri )
print_req_type_helpers ( ri )
2023-01-20 09:50:36 -08:00
if not ri . type_consistent :
print_rsp_type ( ri )
print_wrapped_type ( ri )
print_dump_prototype ( ri )
cw . nl ( )
2023-06-08 14:11:57 -07:00
if op . has_ntf :
2023-01-20 09:50:36 -08:00
cw . p ( f " /* { op . enum_name } - notify */ " )
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , op , ' notify ' )
2023-01-20 09:50:36 -08:00
if not ri . type_consistent :
2023-06-01 19:35:42 -07:00
raise Exception ( f ' Only notifications with consistent types supported ( { op . name } ) ' )
2023-01-20 09:50:36 -08:00
print_wrapped_type ( ri )
2023-06-08 14:11:58 -07:00
for op_name , op in parsed . ntfs . items ( ) :
2023-01-20 09:50:36 -08:00
if ' event ' in op :
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , op , ' event ' )
2023-01-20 09:50:36 -08:00
cw . p ( f " /* { op . enum_name } - event */ " )
print_rsp_type ( ri )
cw . nl ( )
print_wrapped_type ( ri )
cw . nl ( )
else :
2023-06-01 19:35:44 -07:00
cw . p ( ' /* Enums */ ' )
put_op_name ( parsed , cw )
for name , const in parsed . consts . items ( ) :
if isinstance ( const , EnumSet ) :
put_enum_to_str ( parsed , cw , const )
cw . nl ( )
2023-12-13 15:14:32 -08:00
has_recursive_nests = False
2023-01-20 09:50:36 -08:00
cw . p ( ' /* Policies */ ' )
2023-12-13 15:14:32 -08:00
for struct in parsed . pure_nested_structs . values ( ) :
if struct . recursive :
put_typol_fwd ( cw , struct )
has_recursive_nests = True
if has_recursive_nests :
cw . nl ( )
2023-06-07 13:24:00 -07:00
for name in parsed . pure_nested_structs :
2023-01-20 09:50:36 -08:00
struct = Struct ( parsed , name )
2023-06-07 13:24:00 -07:00
put_typol ( cw , struct )
for name in parsed . root_sets :
2023-01-20 09:50:36 -08:00
struct = Struct ( parsed , name )
put_typol ( cw , struct )
cw . p ( ' /* Common nested types */ ' )
2023-12-13 15:14:32 -08:00
if has_recursive_nests :
for attr_set , struct in parsed . pure_nested_structs . items ( ) :
ri = RenderInfo ( cw , parsed , args . mode , " " , " " , attr_set )
free_rsp_nested_prototype ( ri )
if struct . request :
put_req_nested_prototype ( ri , struct )
if struct . reply :
parse_rsp_nested_prototype ( ri , struct )
cw . nl ( )
2023-06-07 13:23:57 -07:00
for attr_set , struct in parsed . pure_nested_structs . items ( ) :
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , " " , " " , attr_set )
2023-01-20 09:50:36 -08:00
free_rsp_nested ( ri , struct )
if struct . request :
put_req_nested ( ri , struct )
if struct . reply :
parse_rsp_nested ( ri , struct )
for op_name , op in parsed . ops . items ( ) :
cw . p ( f " /* ============== { op . enum_name } ============== */ " )
if ' do ' in op and ' event ' not in op :
cw . p ( f " /* { op . enum_name } - do */ " )
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , op , " do " )
2023-06-01 19:35:46 -07:00
print_req_free ( ri )
2023-01-20 09:50:36 -08:00
print_rsp_free ( ri )
parse_rsp_msg ( ri )
print_req ( ri )
cw . nl ( )
if ' dump ' in op :
cw . p ( f " /* { op . enum_name } - dump */ " )
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , op , " dump " )
2023-01-20 09:50:36 -08:00
if not ri . type_consistent :
parse_rsp_msg ( ri , deref = True )
2023-12-13 15:14:25 -08:00
print_req_free ( ri )
2023-01-20 09:50:36 -08:00
print_dump_type_free ( ri )
print_dump ( ri )
cw . nl ( )
2023-06-08 14:11:57 -07:00
if op . has_ntf :
2023-01-20 09:50:36 -08:00
cw . p ( f " /* { op . enum_name } - notify */ " )
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , op , ' notify ' )
2023-01-20 09:50:36 -08:00
if not ri . type_consistent :
2023-06-01 19:35:42 -07:00
raise Exception ( f ' Only notifications with consistent types supported ( { op . name } ) ' )
2023-01-20 09:50:36 -08:00
print_ntf_type_free ( ri )
2023-06-08 14:11:58 -07:00
for op_name , op in parsed . ntfs . items ( ) :
2023-01-20 09:50:36 -08:00
if ' event ' in op :
cw . p ( f " /* { op . enum_name } - event */ " )
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , op , " do " )
2023-01-20 09:50:36 -08:00
parse_rsp_msg ( ri )
2023-06-08 14:11:59 -07:00
ri = RenderInfo ( cw , parsed , args . mode , op , " event " )
2023-01-20 09:50:36 -08:00
print_ntf_type_free ( ri )
2023-06-01 19:35:47 -07:00
cw . nl ( )
render_user_family ( parsed , cw , False )
2023-01-20 09:50:36 -08:00
if args . header :
cw . p ( f ' #endif /* { hdr_prot } */ ' )
if __name__ == " __main__ " :
main ( )