1981cbcb0SJakub Kicinski#!/usr/bin/env python3 24e16b6a7SJakub Kicinski# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 3be5bea1cSJakub Kicinski 4be5bea1cSJakub Kicinskiimport argparse 53a43ded0SJakub Kicinskiimport collections 6be5bea1cSJakub Kicinskiimport os 7008bcd68SJakub Kicinskiimport re 8f65f305aSJiri Pirkoimport shutil 9f65f305aSJiri Pirkoimport tempfile 10be5bea1cSJakub Kicinskiimport yaml 11be5bea1cSJakub Kicinski 126517a60bSJakub Kicinskifrom lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry 1330a5c6c8SJakub Kicinski 14be5bea1cSJakub Kicinski 15be5bea1cSJakub Kicinskidef c_upper(name): 16be5bea1cSJakub Kicinski return name.upper().replace('-', '_') 17be5bea1cSJakub Kicinski 18be5bea1cSJakub Kicinski 19be5bea1cSJakub Kicinskidef c_lower(name): 20be5bea1cSJakub Kicinski return name.lower().replace('-', '_') 21be5bea1cSJakub Kicinski 22be5bea1cSJakub Kicinski 23be5bea1cSJakub Kicinskiclass BaseNlLib: 24be5bea1cSJakub Kicinski def get_family_id(self): 25be5bea1cSJakub Kicinski return 'ys->family_id' 26be5bea1cSJakub Kicinski 27be5bea1cSJakub Kicinski def parse_cb_run(self, cb, data, is_dump=False, indent=1): 28be5bea1cSJakub Kicinski ind = '\n\t\t' + '\t' * indent + ' ' 29be5bea1cSJakub Kicinski if is_dump: 30be5bea1cSJakub Kicinski return f"mnl_cb_run2(ys->rx_buf, len, 0, 0, {cb}, {data},{ind}ynl_cb_array, NLMSG_MIN_TYPE)" 31be5bea1cSJakub Kicinski else: 32be5bea1cSJakub Kicinski return f"mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid,{ind}{cb}, {data},{ind}" + \ 33be5bea1cSJakub Kicinski "ynl_cb_array, NLMSG_MIN_TYPE)" 34be5bea1cSJakub Kicinski 35be5bea1cSJakub Kicinski 3630a5c6c8SJakub Kicinskiclass Type(SpecAttr): 3730a5c6c8SJakub Kicinski def __init__(self, family, attr_set, attr, value): 3830a5c6c8SJakub Kicinski super().__init__(family, attr_set, attr, value) 3930a5c6c8SJakub Kicinski 40be5bea1cSJakub Kicinski self.attr = attr 4130a5c6c8SJakub Kicinski self.attr_set = attr_set 42be5bea1cSJakub Kicinski self.type = attr['type'] 43be5bea1cSJakub Kicinski self.checks = attr.get('checks', {}) 44be5bea1cSJakub Kicinski 45be5bea1cSJakub Kicinski if 'len' in attr: 46be5bea1cSJakub Kicinski self.len = attr['len'] 47be5bea1cSJakub Kicinski if 'nested-attributes' in attr: 48be5bea1cSJakub Kicinski self.nested_attrs = attr['nested-attributes'] 49be5bea1cSJakub Kicinski if self.nested_attrs == family.name: 50be5bea1cSJakub Kicinski self.nested_render_name = f"{family.name}" 51be5bea1cSJakub Kicinski else: 52be5bea1cSJakub Kicinski self.nested_render_name = f"{family.name}_{c_lower(self.nested_attrs)}" 53be5bea1cSJakub Kicinski 542c9d47a0SJakub Kicinski if self.nested_attrs in self.family.consts: 552c9d47a0SJakub Kicinski self.nested_struct_type = 'struct ' + self.nested_render_name + '_' 562c9d47a0SJakub Kicinski else: 572c9d47a0SJakub Kicinski self.nested_struct_type = 'struct ' + self.nested_render_name 582c9d47a0SJakub Kicinski 59be5bea1cSJakub Kicinski self.c_name = c_lower(self.name) 60be5bea1cSJakub Kicinski if self.c_name in _C_KW: 61be5bea1cSJakub Kicinski self.c_name += '_' 62be5bea1cSJakub Kicinski 6330a5c6c8SJakub Kicinski # Added by resolve(): 6430a5c6c8SJakub Kicinski self.enum_name = None 6530a5c6c8SJakub Kicinski delattr(self, "enum_name") 66be5bea1cSJakub Kicinski 6730a5c6c8SJakub Kicinski def resolve(self): 68ed2042ccSJakub Kicinski if 'name-prefix' in self.attr: 69ed2042ccSJakub Kicinski enum_name = f"{self.attr['name-prefix']}{self.name}" 70ed2042ccSJakub Kicinski else: 71ed2042ccSJakub Kicinski enum_name = f"{self.attr_set.name_prefix}{self.name}" 72ed2042ccSJakub Kicinski self.enum_name = c_upper(enum_name) 73be5bea1cSJakub Kicinski 74be5bea1cSJakub Kicinski def is_multi_val(self): 75be5bea1cSJakub Kicinski return None 76be5bea1cSJakub Kicinski 77be5bea1cSJakub Kicinski def is_scalar(self): 78be5bea1cSJakub Kicinski return self.type in {'u8', 'u16', 'u32', 'u64', 's32', 's64'} 79be5bea1cSJakub Kicinski 80be5bea1cSJakub Kicinski def presence_type(self): 81be5bea1cSJakub Kicinski return 'bit' 82be5bea1cSJakub Kicinski 83be5bea1cSJakub Kicinski def presence_member(self, space, type_filter): 84be5bea1cSJakub Kicinski if self.presence_type() != type_filter: 85be5bea1cSJakub Kicinski return 86be5bea1cSJakub Kicinski 87be5bea1cSJakub Kicinski if self.presence_type() == 'bit': 88be5bea1cSJakub Kicinski pfx = '__' if space == 'user' else '' 89be5bea1cSJakub Kicinski return f"{pfx}u32 {self.c_name}:1;" 90be5bea1cSJakub Kicinski 91be5bea1cSJakub Kicinski if self.presence_type() == 'len': 92be5bea1cSJakub Kicinski pfx = '__' if space == 'user' else '' 93be5bea1cSJakub Kicinski return f"{pfx}u32 {self.c_name}_len;" 94be5bea1cSJakub Kicinski 95be5bea1cSJakub Kicinski def _complex_member_type(self, ri): 96be5bea1cSJakub Kicinski return None 97be5bea1cSJakub Kicinski 98be5bea1cSJakub Kicinski def free_needs_iter(self): 99be5bea1cSJakub Kicinski return False 100be5bea1cSJakub Kicinski 101be5bea1cSJakub Kicinski def free(self, ri, var, ref): 102be5bea1cSJakub Kicinski if self.is_multi_val() or self.presence_type() == 'len': 103be5bea1cSJakub Kicinski ri.cw.p(f'free({var}->{ref}{self.c_name});') 104be5bea1cSJakub Kicinski 105be5bea1cSJakub Kicinski def arg_member(self, ri): 106be5bea1cSJakub Kicinski member = self._complex_member_type(ri) 107be5bea1cSJakub Kicinski if member: 1082cc9671aSJakub Kicinski arg = [member + ' *' + self.c_name] 1092cc9671aSJakub Kicinski if self.presence_type() == 'count': 1102cc9671aSJakub Kicinski arg += ['unsigned int n_' + self.c_name] 1112cc9671aSJakub Kicinski return arg 112be5bea1cSJakub Kicinski raise Exception(f"Struct member not implemented for class type {self.type}") 113be5bea1cSJakub Kicinski 114be5bea1cSJakub Kicinski def struct_member(self, ri): 115be5bea1cSJakub Kicinski if self.is_multi_val(): 116be5bea1cSJakub Kicinski ri.cw.p(f"unsigned int n_{self.c_name};") 117be5bea1cSJakub Kicinski member = self._complex_member_type(ri) 118be5bea1cSJakub Kicinski if member: 119be5bea1cSJakub Kicinski ptr = '*' if self.is_multi_val() else '' 120be5bea1cSJakub Kicinski ri.cw.p(f"{member} {ptr}{self.c_name};") 121be5bea1cSJakub Kicinski return 122be5bea1cSJakub Kicinski members = self.arg_member(ri) 123be5bea1cSJakub Kicinski for one in members: 124be5bea1cSJakub Kicinski ri.cw.p(one + ';') 125be5bea1cSJakub Kicinski 126be5bea1cSJakub Kicinski def _attr_policy(self, policy): 127be5bea1cSJakub Kicinski return '{ .type = ' + policy + ', }' 128be5bea1cSJakub Kicinski 129be5bea1cSJakub Kicinski def attr_policy(self, cw): 130be5bea1cSJakub Kicinski policy = c_upper('nla-' + self.attr['type']) 131be5bea1cSJakub Kicinski 132be5bea1cSJakub Kicinski spec = self._attr_policy(policy) 133be5bea1cSJakub Kicinski cw.p(f"\t[{self.enum_name}] = {spec},") 134be5bea1cSJakub Kicinski 135be5bea1cSJakub Kicinski def _attr_typol(self): 136be5bea1cSJakub Kicinski raise Exception(f"Type policy not implemented for class type {self.type}") 137be5bea1cSJakub Kicinski 138be5bea1cSJakub Kicinski def attr_typol(self, cw): 139be5bea1cSJakub Kicinski typol = self._attr_typol() 140be5bea1cSJakub Kicinski cw.p(f'[{self.enum_name}] = {"{"} .name = "{self.name}", {typol}{"}"},') 141be5bea1cSJakub Kicinski 142be5bea1cSJakub Kicinski def _attr_put_line(self, ri, var, line): 143be5bea1cSJakub Kicinski if self.presence_type() == 'bit': 144be5bea1cSJakub Kicinski ri.cw.p(f"if ({var}->_present.{self.c_name})") 145be5bea1cSJakub Kicinski elif self.presence_type() == 'len': 146be5bea1cSJakub Kicinski ri.cw.p(f"if ({var}->_present.{self.c_name}_len)") 147be5bea1cSJakub Kicinski ri.cw.p(f"{line};") 148be5bea1cSJakub Kicinski 149be5bea1cSJakub Kicinski def _attr_put_simple(self, ri, var, put_type): 150be5bea1cSJakub Kicinski line = f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})" 151be5bea1cSJakub Kicinski self._attr_put_line(ri, var, line) 152be5bea1cSJakub Kicinski 153be5bea1cSJakub Kicinski def attr_put(self, ri, var): 154be5bea1cSJakub Kicinski raise Exception(f"Put not implemented for class type {self.type}") 155be5bea1cSJakub Kicinski 156be5bea1cSJakub Kicinski def _attr_get(self, ri, var): 157be5bea1cSJakub Kicinski raise Exception(f"Attr get not implemented for class type {self.type}") 158be5bea1cSJakub Kicinski 159be5bea1cSJakub Kicinski def attr_get(self, ri, var, first): 160be5bea1cSJakub Kicinski lines, init_lines, local_vars = self._attr_get(ri, var) 161be5bea1cSJakub Kicinski if type(lines) is str: 162be5bea1cSJakub Kicinski lines = [lines] 163be5bea1cSJakub Kicinski if type(init_lines) is str: 164be5bea1cSJakub Kicinski init_lines = [init_lines] 165be5bea1cSJakub Kicinski 166be5bea1cSJakub Kicinski kw = 'if' if first else 'else if' 167e4ea3cc6SJakub Kicinski ri.cw.block_start(line=f"{kw} (type == {self.enum_name})") 168be5bea1cSJakub Kicinski if local_vars: 169be5bea1cSJakub Kicinski for local in local_vars: 170be5bea1cSJakub Kicinski ri.cw.p(local) 171be5bea1cSJakub Kicinski ri.cw.nl() 172be5bea1cSJakub Kicinski 173be5bea1cSJakub Kicinski if not self.is_multi_val(): 174be5bea1cSJakub Kicinski ri.cw.p("if (ynl_attr_validate(yarg, attr))") 175be5bea1cSJakub Kicinski ri.cw.p("return MNL_CB_ERROR;") 176be5bea1cSJakub Kicinski if self.presence_type() == 'bit': 177be5bea1cSJakub Kicinski ri.cw.p(f"{var}->_present.{self.c_name} = 1;") 178be5bea1cSJakub Kicinski 179be5bea1cSJakub Kicinski if init_lines: 180be5bea1cSJakub Kicinski ri.cw.nl() 181be5bea1cSJakub Kicinski for line in init_lines: 182be5bea1cSJakub Kicinski ri.cw.p(line) 183be5bea1cSJakub Kicinski 184be5bea1cSJakub Kicinski for line in lines: 185be5bea1cSJakub Kicinski ri.cw.p(line) 186be5bea1cSJakub Kicinski ri.cw.block_end() 1876ad49839SJakub Kicinski return True 188be5bea1cSJakub Kicinski 189be5bea1cSJakub Kicinski def _setter_lines(self, ri, member, presence): 190be5bea1cSJakub Kicinski raise Exception(f"Setter not implemented for class type {self.type}") 191be5bea1cSJakub Kicinski 192be5bea1cSJakub Kicinski def setter(self, ri, space, direction, deref=False, ref=None): 193be5bea1cSJakub Kicinski ref = (ref if ref else []) + [self.c_name] 194be5bea1cSJakub Kicinski var = "req" 195be5bea1cSJakub Kicinski member = f"{var}->{'.'.join(ref)}" 196be5bea1cSJakub Kicinski 197be5bea1cSJakub Kicinski code = [] 198be5bea1cSJakub Kicinski presence = '' 199be5bea1cSJakub Kicinski for i in range(0, len(ref)): 200be5bea1cSJakub Kicinski presence = f"{var}->{'.'.join(ref[:i] + [''])}_present.{ref[i]}" 201*5c05bdd9SJakub Kicinski # Every layer below last is a nest, so we know it uses bit presence 202*5c05bdd9SJakub Kicinski # last layer is "self" and may be a complex type 203*5c05bdd9SJakub Kicinski if i == len(ref) - 1 and self.presence_type() != 'bit': 204*5c05bdd9SJakub Kicinski continue 205be5bea1cSJakub Kicinski code.append(presence + ' = 1;') 206be5bea1cSJakub Kicinski code += self._setter_lines(ri, member, presence) 207be5bea1cSJakub Kicinski 2082cc9671aSJakub Kicinski func_name = f"{op_prefix(ri, direction, deref=deref)}_set_{'_'.join(ref)}" 2092cc9671aSJakub Kicinski free = bool([x for x in code if 'free(' in x]) 2102cc9671aSJakub Kicinski alloc = bool([x for x in code if 'alloc(' in x]) 2112cc9671aSJakub Kicinski if free and not alloc: 2122cc9671aSJakub Kicinski func_name = '__' + func_name 2132cc9671aSJakub Kicinski ri.cw.write_func('static inline void', func_name, body=code, 214be5bea1cSJakub Kicinski args=[f'{type_name(ri, direction, deref=deref)} *{var}'] + self.arg_member(ri)) 215be5bea1cSJakub Kicinski 216be5bea1cSJakub Kicinski 217be5bea1cSJakub Kicinskiclass TypeUnused(Type): 218be5bea1cSJakub Kicinski def presence_type(self): 219be5bea1cSJakub Kicinski return '' 220be5bea1cSJakub Kicinski 2216ad49839SJakub Kicinski def arg_member(self, ri): 2226ad49839SJakub Kicinski return [] 2236ad49839SJakub Kicinski 2246ad49839SJakub Kicinski def _attr_get(self, ri, var): 2256ad49839SJakub Kicinski return ['return MNL_CB_ERROR;'], None, None 2266ad49839SJakub Kicinski 227be5bea1cSJakub Kicinski def _attr_typol(self): 228be5bea1cSJakub Kicinski return '.type = YNL_PT_REJECT, ' 229be5bea1cSJakub Kicinski 230be5bea1cSJakub Kicinski def attr_policy(self, cw): 231be5bea1cSJakub Kicinski pass 232be5bea1cSJakub Kicinski 233be5bea1cSJakub Kicinski 234be5bea1cSJakub Kicinskiclass TypePad(Type): 235be5bea1cSJakub Kicinski def presence_type(self): 236be5bea1cSJakub Kicinski return '' 237be5bea1cSJakub Kicinski 2386ad49839SJakub Kicinski def arg_member(self, ri): 2396ad49839SJakub Kicinski return [] 2406ad49839SJakub Kicinski 241be5bea1cSJakub Kicinski def _attr_typol(self): 2426ad49839SJakub Kicinski return '.type = YNL_PT_IGNORE, ' 2436ad49839SJakub Kicinski 24476abff37SJakub Kicinski def attr_put(self, ri, var): 24576abff37SJakub Kicinski pass 24676abff37SJakub Kicinski 2476ad49839SJakub Kicinski def attr_get(self, ri, var, first): 2486ad49839SJakub Kicinski pass 249be5bea1cSJakub Kicinski 250be5bea1cSJakub Kicinski def attr_policy(self, cw): 251be5bea1cSJakub Kicinski pass 252be5bea1cSJakub Kicinski 25376abff37SJakub Kicinski def setter(self, ri, space, direction, deref=False, ref=None): 25476abff37SJakub Kicinski pass 25576abff37SJakub Kicinski 256be5bea1cSJakub Kicinski 257be5bea1cSJakub Kicinskiclass TypeScalar(Type): 25830a5c6c8SJakub Kicinski def __init__(self, family, attr_set, attr, value): 25930a5c6c8SJakub Kicinski super().__init__(family, attr_set, attr, value) 260be5bea1cSJakub Kicinski 261be5bea1cSJakub Kicinski self.byte_order_comment = '' 262be5bea1cSJakub Kicinski if 'byte-order' in attr: 263be5bea1cSJakub Kicinski self.byte_order_comment = f" /* {attr['byte-order']} */" 264be5bea1cSJakub Kicinski 26530a5c6c8SJakub Kicinski # Added by resolve(): 26630a5c6c8SJakub Kicinski self.is_bitfield = None 26730a5c6c8SJakub Kicinski delattr(self, "is_bitfield") 26830a5c6c8SJakub Kicinski self.type_name = None 26930a5c6c8SJakub Kicinski delattr(self, "type_name") 27030a5c6c8SJakub Kicinski 27130a5c6c8SJakub Kicinski def resolve(self): 27230a5c6c8SJakub Kicinski self.resolve_up(super()) 27330a5c6c8SJakub Kicinski 27430a5c6c8SJakub Kicinski if 'enum-as-flags' in self.attr and self.attr['enum-as-flags']: 27530a5c6c8SJakub Kicinski self.is_bitfield = True 27630a5c6c8SJakub Kicinski elif 'enum' in self.attr: 27730a5c6c8SJakub Kicinski self.is_bitfield = self.family.consts[self.attr['enum']]['type'] == 'flags' 27830a5c6c8SJakub Kicinski else: 27930a5c6c8SJakub Kicinski self.is_bitfield = False 28030a5c6c8SJakub Kicinski 281dddc9f53SJakub Kicinski maybe_enum = not self.is_bitfield and 'enum' in self.attr 282dddc9f53SJakub Kicinski if maybe_enum and self.family.consts[self.attr['enum']].enum_name: 28330a5c6c8SJakub Kicinski self.type_name = f"enum {self.family.name}_{c_lower(self.attr['enum'])}" 28430a5c6c8SJakub Kicinski else: 28530a5c6c8SJakub Kicinski self.type_name = '__' + self.type 28630a5c6c8SJakub Kicinski 287be5bea1cSJakub Kicinski def _mnl_type(self): 288be5bea1cSJakub Kicinski t = self.type 289be5bea1cSJakub Kicinski # mnl does not have a helper for signed types 290be5bea1cSJakub Kicinski if t[0] == 's': 291be5bea1cSJakub Kicinski t = 'u' + t[1:] 292be5bea1cSJakub Kicinski return t 293be5bea1cSJakub Kicinski 294be5bea1cSJakub Kicinski def _attr_policy(self, policy): 295be5bea1cSJakub Kicinski if 'flags-mask' in self.checks or self.is_bitfield: 296be5bea1cSJakub Kicinski if self.is_bitfield: 2974c6170d1SJakub Kicinski enum = self.family.consts[self.attr['enum']] 2984c6170d1SJakub Kicinski mask = enum.get_mask(as_flags=True) 299be5bea1cSJakub Kicinski else: 300be5bea1cSJakub Kicinski flags = self.family.consts[self.checks['flags-mask']] 301be5bea1cSJakub Kicinski flag_cnt = len(flags['entries']) 302be5bea1cSJakub Kicinski mask = (1 << flag_cnt) - 1 303be5bea1cSJakub Kicinski return f"NLA_POLICY_MASK({policy}, 0x{mask:x})" 304be5bea1cSJakub Kicinski elif 'min' in self.checks: 305be5bea1cSJakub Kicinski return f"NLA_POLICY_MIN({policy}, {self.checks['min']})" 306be5bea1cSJakub Kicinski elif 'enum' in self.attr: 307be5bea1cSJakub Kicinski enum = self.family.consts[self.attr['enum']] 30810c4d2a7SJakub Kicinski low, high = enum.value_range() 30910c4d2a7SJakub Kicinski if low == 0: 31010c4d2a7SJakub Kicinski return f"NLA_POLICY_MAX({policy}, {high})" 31110c4d2a7SJakub Kicinski return f"NLA_POLICY_RANGE({policy}, {low}, {high})" 312be5bea1cSJakub Kicinski return super()._attr_policy(policy) 313be5bea1cSJakub Kicinski 314be5bea1cSJakub Kicinski def _attr_typol(self): 315be5bea1cSJakub Kicinski return f'.type = YNL_PT_U{self.type[1:]}, ' 316be5bea1cSJakub Kicinski 317be5bea1cSJakub Kicinski def arg_member(self, ri): 318be5bea1cSJakub Kicinski return [f'{self.type_name} {self.c_name}{self.byte_order_comment}'] 319be5bea1cSJakub Kicinski 320be5bea1cSJakub Kicinski def attr_put(self, ri, var): 321be5bea1cSJakub Kicinski self._attr_put_simple(ri, var, self._mnl_type()) 322be5bea1cSJakub Kicinski 323be5bea1cSJakub Kicinski def _attr_get(self, ri, var): 324be5bea1cSJakub Kicinski return f"{var}->{self.c_name} = mnl_attr_get_{self._mnl_type()}(attr);", None, None 325be5bea1cSJakub Kicinski 326be5bea1cSJakub Kicinski def _setter_lines(self, ri, member, presence): 327be5bea1cSJakub Kicinski return [f"{member} = {self.c_name};"] 328be5bea1cSJakub Kicinski 329be5bea1cSJakub Kicinski 330be5bea1cSJakub Kicinskiclass TypeFlag(Type): 331be5bea1cSJakub Kicinski def arg_member(self, ri): 332be5bea1cSJakub Kicinski return [] 333be5bea1cSJakub Kicinski 334be5bea1cSJakub Kicinski def _attr_typol(self): 335be5bea1cSJakub Kicinski return '.type = YNL_PT_FLAG, ' 336be5bea1cSJakub Kicinski 337be5bea1cSJakub Kicinski def attr_put(self, ri, var): 338be5bea1cSJakub Kicinski self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, 0, NULL)") 339be5bea1cSJakub Kicinski 340be5bea1cSJakub Kicinski def _attr_get(self, ri, var): 341be5bea1cSJakub Kicinski return [], None, None 342be5bea1cSJakub Kicinski 343be5bea1cSJakub Kicinski def _setter_lines(self, ri, member, presence): 344be5bea1cSJakub Kicinski return [] 345be5bea1cSJakub Kicinski 346be5bea1cSJakub Kicinski 347be5bea1cSJakub Kicinskiclass TypeString(Type): 348be5bea1cSJakub Kicinski def arg_member(self, ri): 349be5bea1cSJakub Kicinski return [f"const char *{self.c_name}"] 350be5bea1cSJakub Kicinski 351be5bea1cSJakub Kicinski def presence_type(self): 352be5bea1cSJakub Kicinski return 'len' 353be5bea1cSJakub Kicinski 354be5bea1cSJakub Kicinski def struct_member(self, ri): 355be5bea1cSJakub Kicinski ri.cw.p(f"char *{self.c_name};") 356be5bea1cSJakub Kicinski 357be5bea1cSJakub Kicinski def _attr_typol(self): 358be5bea1cSJakub Kicinski return f'.type = YNL_PT_NUL_STR, ' 359be5bea1cSJakub Kicinski 360be5bea1cSJakub Kicinski def _attr_policy(self, policy): 361be5bea1cSJakub Kicinski mem = '{ .type = ' + policy 362be5bea1cSJakub Kicinski if 'max-len' in self.checks: 363be5bea1cSJakub Kicinski mem += ', .len = ' + str(self.checks['max-len']) 364be5bea1cSJakub Kicinski mem += ', }' 365be5bea1cSJakub Kicinski return mem 366be5bea1cSJakub Kicinski 367be5bea1cSJakub Kicinski def attr_policy(self, cw): 368be5bea1cSJakub Kicinski if self.checks.get('unterminated-ok', False): 369be5bea1cSJakub Kicinski policy = 'NLA_STRING' 370be5bea1cSJakub Kicinski else: 371be5bea1cSJakub Kicinski policy = 'NLA_NUL_STRING' 372be5bea1cSJakub Kicinski 373be5bea1cSJakub Kicinski spec = self._attr_policy(policy) 374be5bea1cSJakub Kicinski cw.p(f"\t[{self.enum_name}] = {spec},") 375be5bea1cSJakub Kicinski 376be5bea1cSJakub Kicinski def attr_put(self, ri, var): 377be5bea1cSJakub Kicinski self._attr_put_simple(ri, var, 'strz') 378be5bea1cSJakub Kicinski 379be5bea1cSJakub Kicinski def _attr_get(self, ri, var): 380be5bea1cSJakub Kicinski len_mem = var + '->_present.' + self.c_name + '_len' 381be5bea1cSJakub Kicinski return [f"{len_mem} = len;", 382be5bea1cSJakub Kicinski f"{var}->{self.c_name} = malloc(len + 1);", 383be5bea1cSJakub Kicinski f"memcpy({var}->{self.c_name}, mnl_attr_get_str(attr), len);", 384be5bea1cSJakub Kicinski f"{var}->{self.c_name}[len] = 0;"], \ 385be5bea1cSJakub Kicinski ['len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr));'], \ 386be5bea1cSJakub Kicinski ['unsigned int len;'] 387be5bea1cSJakub Kicinski 388be5bea1cSJakub Kicinski def _setter_lines(self, ri, member, presence): 389be5bea1cSJakub Kicinski return [f"free({member});", 390be5bea1cSJakub Kicinski f"{presence}_len = strlen({self.c_name});", 391be5bea1cSJakub Kicinski f"{member} = malloc({presence}_len + 1);", 392be5bea1cSJakub Kicinski f'memcpy({member}, {self.c_name}, {presence}_len);', 393be5bea1cSJakub Kicinski f'{member}[{presence}_len] = 0;'] 394be5bea1cSJakub Kicinski 395be5bea1cSJakub Kicinski 396be5bea1cSJakub Kicinskiclass TypeBinary(Type): 397be5bea1cSJakub Kicinski def arg_member(self, ri): 398be5bea1cSJakub Kicinski return [f"const void *{self.c_name}", 'size_t len'] 399be5bea1cSJakub Kicinski 400be5bea1cSJakub Kicinski def presence_type(self): 401be5bea1cSJakub Kicinski return 'len' 402be5bea1cSJakub Kicinski 403be5bea1cSJakub Kicinski def struct_member(self, ri): 404be5bea1cSJakub Kicinski ri.cw.p(f"void *{self.c_name};") 405be5bea1cSJakub Kicinski 406be5bea1cSJakub Kicinski def _attr_typol(self): 407be5bea1cSJakub Kicinski return f'.type = YNL_PT_BINARY,' 408be5bea1cSJakub Kicinski 409be5bea1cSJakub Kicinski def _attr_policy(self, policy): 410be5bea1cSJakub Kicinski mem = '{ ' 411be5bea1cSJakub Kicinski if len(self.checks) == 1 and 'min-len' in self.checks: 412be5bea1cSJakub Kicinski mem += '.len = ' + str(self.checks['min-len']) 413be5bea1cSJakub Kicinski elif len(self.checks) == 0: 414be5bea1cSJakub Kicinski mem += '.type = NLA_BINARY' 415be5bea1cSJakub Kicinski else: 416be5bea1cSJakub Kicinski raise Exception('One or more of binary type checks not implemented, yet') 417be5bea1cSJakub Kicinski mem += ', }' 418be5bea1cSJakub Kicinski return mem 419be5bea1cSJakub Kicinski 420be5bea1cSJakub Kicinski def attr_put(self, ri, var): 421be5bea1cSJakub Kicinski self._attr_put_line(ri, var, f"mnl_attr_put(nlh, {self.enum_name}, " + 422be5bea1cSJakub Kicinski f"{var}->_present.{self.c_name}_len, {var}->{self.c_name})") 423be5bea1cSJakub Kicinski 424be5bea1cSJakub Kicinski def _attr_get(self, ri, var): 425be5bea1cSJakub Kicinski len_mem = var + '->_present.' + self.c_name + '_len' 426be5bea1cSJakub Kicinski return [f"{len_mem} = len;", 427be5bea1cSJakub Kicinski f"{var}->{self.c_name} = malloc(len);", 428be5bea1cSJakub Kicinski f"memcpy({var}->{self.c_name}, mnl_attr_get_payload(attr), len);"], \ 429be5bea1cSJakub Kicinski ['len = mnl_attr_get_payload_len(attr);'], \ 430be5bea1cSJakub Kicinski ['unsigned int len;'] 431be5bea1cSJakub Kicinski 432be5bea1cSJakub Kicinski def _setter_lines(self, ri, member, presence): 433be5bea1cSJakub Kicinski return [f"free({member});", 434a149a3a1SJakub Kicinski f"{presence}_len = len;", 435be5bea1cSJakub Kicinski f"{member} = malloc({presence}_len);", 436be5bea1cSJakub Kicinski f'memcpy({member}, {self.c_name}, {presence}_len);'] 437be5bea1cSJakub Kicinski 438be5bea1cSJakub Kicinski 439be5bea1cSJakub Kicinskiclass TypeNest(Type): 440be5bea1cSJakub Kicinski def _complex_member_type(self, ri): 4412c9d47a0SJakub Kicinski return self.nested_struct_type 442be5bea1cSJakub Kicinski 443be5bea1cSJakub Kicinski def free(self, ri, var, ref): 444be5bea1cSJakub Kicinski ri.cw.p(f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name});') 445be5bea1cSJakub Kicinski 446be5bea1cSJakub Kicinski def _attr_typol(self): 447be5bea1cSJakub Kicinski return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' 448be5bea1cSJakub Kicinski 449be5bea1cSJakub Kicinski def _attr_policy(self, policy): 450be5bea1cSJakub Kicinski return 'NLA_POLICY_NESTED(' + self.nested_render_name + '_nl_policy)' 451be5bea1cSJakub Kicinski 452be5bea1cSJakub Kicinski def attr_put(self, ri, var): 453be5bea1cSJakub Kicinski self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " + 454be5bea1cSJakub Kicinski f"{self.enum_name}, &{var}->{self.c_name})") 455be5bea1cSJakub Kicinski 456be5bea1cSJakub Kicinski def _attr_get(self, ri, var): 457eef9b794SJakub Kicinski get_lines = [f"if ({self.nested_render_name}_parse(&parg, attr))", 458eef9b794SJakub Kicinski "return MNL_CB_ERROR;"] 459be5bea1cSJakub Kicinski init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;", 460be5bea1cSJakub Kicinski f"parg.data = &{var}->{self.c_name};"] 461be5bea1cSJakub Kicinski return get_lines, init_lines, None 462be5bea1cSJakub Kicinski 463be5bea1cSJakub Kicinski def setter(self, ri, space, direction, deref=False, ref=None): 464be5bea1cSJakub Kicinski ref = (ref if ref else []) + [self.c_name] 465be5bea1cSJakub Kicinski 466be5bea1cSJakub Kicinski for _, attr in ri.family.pure_nested_structs[self.nested_attrs].member_list(): 467be5bea1cSJakub Kicinski attr.setter(ri, self.nested_attrs, direction, deref=deref, ref=ref) 468be5bea1cSJakub Kicinski 469be5bea1cSJakub Kicinski 470be5bea1cSJakub Kicinskiclass TypeMultiAttr(Type): 471be093a80SJakub Kicinski def __init__(self, family, attr_set, attr, value, base_type): 472be093a80SJakub Kicinski super().__init__(family, attr_set, attr, value) 473be093a80SJakub Kicinski 474be093a80SJakub Kicinski self.base_type = base_type 475be093a80SJakub Kicinski 476be5bea1cSJakub Kicinski def is_multi_val(self): 477be5bea1cSJakub Kicinski return True 478be5bea1cSJakub Kicinski 479be5bea1cSJakub Kicinski def presence_type(self): 480be5bea1cSJakub Kicinski return 'count' 481be5bea1cSJakub Kicinski 4822cc9671aSJakub Kicinski def _mnl_type(self): 4832cc9671aSJakub Kicinski t = self.type 4842cc9671aSJakub Kicinski # mnl does not have a helper for signed types 4852cc9671aSJakub Kicinski if t[0] == 's': 4862cc9671aSJakub Kicinski t = 'u' + t[1:] 4872cc9671aSJakub Kicinski return t 4882cc9671aSJakub Kicinski 489be5bea1cSJakub Kicinski def _complex_member_type(self, ri): 490be5bea1cSJakub Kicinski if 'type' not in self.attr or self.attr['type'] == 'nest': 4912c9d47a0SJakub Kicinski return self.nested_struct_type 492be5bea1cSJakub Kicinski elif self.attr['type'] in scalars: 493be5bea1cSJakub Kicinski scalar_pfx = '__' if ri.ku_space == 'user' else '' 494be5bea1cSJakub Kicinski return scalar_pfx + self.attr['type'] 495be5bea1cSJakub Kicinski else: 496be5bea1cSJakub Kicinski raise Exception(f"Sub-type {self.attr['type']} not supported yet") 497be5bea1cSJakub Kicinski 498be5bea1cSJakub Kicinski def free_needs_iter(self): 499be5bea1cSJakub Kicinski return 'type' not in self.attr or self.attr['type'] == 'nest' 500be5bea1cSJakub Kicinski 501be5bea1cSJakub Kicinski def free(self, ri, var, ref): 5022cc9671aSJakub Kicinski if self.attr['type'] in scalars: 5032cc9671aSJakub Kicinski ri.cw.p(f"free({var}->{ref}{self.c_name});") 5042cc9671aSJakub Kicinski elif 'type' not in self.attr or self.attr['type'] == 'nest': 505be5bea1cSJakub Kicinski ri.cw.p(f"for (i = 0; i < {var}->{ref}n_{self.c_name}; i++)") 506be5bea1cSJakub Kicinski ri.cw.p(f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);') 5072cc9671aSJakub Kicinski ri.cw.p(f"free({var}->{ref}{self.c_name});") 5082cc9671aSJakub Kicinski else: 5092cc9671aSJakub Kicinski raise Exception(f"Free of MultiAttr sub-type {self.attr['type']} not supported yet") 510be5bea1cSJakub Kicinski 511be093a80SJakub Kicinski def _attr_policy(self, policy): 512be093a80SJakub Kicinski return self.base_type._attr_policy(policy) 513be093a80SJakub Kicinski 514be5bea1cSJakub Kicinski def _attr_typol(self): 515be093a80SJakub Kicinski return self.base_type._attr_typol() 516be5bea1cSJakub Kicinski 517be5bea1cSJakub Kicinski def _attr_get(self, ri, var): 51858da455bSJakub Kicinski return f'n_{self.c_name}++;', None, None 519be5bea1cSJakub Kicinski 5202cc9671aSJakub Kicinski def attr_put(self, ri, var): 5212cc9671aSJakub Kicinski if self.attr['type'] in scalars: 5222cc9671aSJakub Kicinski put_type = self._mnl_type() 5232cc9671aSJakub Kicinski ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)") 5242cc9671aSJakub Kicinski ri.cw.p(f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);") 5252cc9671aSJakub Kicinski elif 'type' not in self.attr or self.attr['type'] == 'nest': 5262cc9671aSJakub Kicinski ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)") 5272cc9671aSJakub Kicinski self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " + 5282cc9671aSJakub Kicinski f"{self.enum_name}, &{var}->{self.c_name}[i])") 5292cc9671aSJakub Kicinski else: 5302cc9671aSJakub Kicinski raise Exception(f"Put of MultiAttr sub-type {self.attr['type']} not supported yet") 5312cc9671aSJakub Kicinski 5322cc9671aSJakub Kicinski def _setter_lines(self, ri, member, presence): 5332cc9671aSJakub Kicinski # For multi-attr we have a count, not presence, hack up the presence 5342cc9671aSJakub Kicinski presence = presence[:-(len('_present.') + len(self.c_name))] + "n_" + self.c_name 5352cc9671aSJakub Kicinski return [f"free({member});", 5362cc9671aSJakub Kicinski f"{member} = {self.c_name};", 5372cc9671aSJakub Kicinski f"{presence} = n_{self.c_name};"] 5382cc9671aSJakub Kicinski 539be5bea1cSJakub Kicinski 540be5bea1cSJakub Kicinskiclass TypeArrayNest(Type): 541be5bea1cSJakub Kicinski def is_multi_val(self): 542be5bea1cSJakub Kicinski return True 543be5bea1cSJakub Kicinski 544be5bea1cSJakub Kicinski def presence_type(self): 545be5bea1cSJakub Kicinski return 'count' 546be5bea1cSJakub Kicinski 547be5bea1cSJakub Kicinski def _complex_member_type(self, ri): 548be5bea1cSJakub Kicinski if 'sub-type' not in self.attr or self.attr['sub-type'] == 'nest': 5492c9d47a0SJakub Kicinski return self.nested_struct_type 550be5bea1cSJakub Kicinski elif self.attr['sub-type'] in scalars: 551be5bea1cSJakub Kicinski scalar_pfx = '__' if ri.ku_space == 'user' else '' 552be5bea1cSJakub Kicinski return scalar_pfx + self.attr['sub-type'] 553be5bea1cSJakub Kicinski else: 554be5bea1cSJakub Kicinski raise Exception(f"Sub-type {self.attr['sub-type']} not supported yet") 555be5bea1cSJakub Kicinski 556be5bea1cSJakub Kicinski def _attr_typol(self): 557be5bea1cSJakub Kicinski return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' 558be5bea1cSJakub Kicinski 559be5bea1cSJakub Kicinski def _attr_get(self, ri, var): 560be5bea1cSJakub Kicinski local_vars = ['const struct nlattr *attr2;'] 561be5bea1cSJakub Kicinski get_lines = [f'attr_{self.c_name} = attr;', 562be5bea1cSJakub Kicinski 'mnl_attr_for_each_nested(attr2, attr)', 563be5bea1cSJakub Kicinski f'\t{var}->n_{self.c_name}++;'] 564be5bea1cSJakub Kicinski return get_lines, None, local_vars 565be5bea1cSJakub Kicinski 566be5bea1cSJakub Kicinski 567be5bea1cSJakub Kicinskiclass TypeNestTypeValue(Type): 568be5bea1cSJakub Kicinski def _complex_member_type(self, ri): 5692c9d47a0SJakub Kicinski return self.nested_struct_type 570be5bea1cSJakub Kicinski 571be5bea1cSJakub Kicinski def _attr_typol(self): 572be5bea1cSJakub Kicinski return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' 573be5bea1cSJakub Kicinski 574be5bea1cSJakub Kicinski def _attr_get(self, ri, var): 575be5bea1cSJakub Kicinski prev = 'attr' 576be5bea1cSJakub Kicinski tv_args = '' 577be5bea1cSJakub Kicinski get_lines = [] 578be5bea1cSJakub Kicinski local_vars = [] 579be5bea1cSJakub Kicinski init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;", 580be5bea1cSJakub Kicinski f"parg.data = &{var}->{self.c_name};"] 581be5bea1cSJakub Kicinski if 'type-value' in self.attr: 582be5bea1cSJakub Kicinski tv_names = [c_lower(x) for x in self.attr["type-value"]] 583be5bea1cSJakub Kicinski local_vars += [f'const struct nlattr *attr_{", *attr_".join(tv_names)};'] 584be5bea1cSJakub Kicinski local_vars += [f'__u32 {", ".join(tv_names)};'] 585be5bea1cSJakub Kicinski for level in self.attr["type-value"]: 586be5bea1cSJakub Kicinski level = c_lower(level) 587be5bea1cSJakub Kicinski get_lines += [f'attr_{level} = mnl_attr_get_payload({prev});'] 588be5bea1cSJakub Kicinski get_lines += [f'{level} = mnl_attr_get_type(attr_{level});'] 589be5bea1cSJakub Kicinski prev = 'attr_' + level 590be5bea1cSJakub Kicinski 591be5bea1cSJakub Kicinski tv_args = f", {', '.join(tv_names)}" 592be5bea1cSJakub Kicinski 593be5bea1cSJakub Kicinski get_lines += [f"{self.nested_render_name}_parse(&parg, {prev}{tv_args});"] 594be5bea1cSJakub Kicinski return get_lines, init_lines, local_vars 595be5bea1cSJakub Kicinski 596be5bea1cSJakub Kicinski 597be5bea1cSJakub Kicinskiclass Struct: 598be5bea1cSJakub Kicinski def __init__(self, family, space_name, type_list=None, inherited=None): 599be5bea1cSJakub Kicinski self.family = family 600be5bea1cSJakub Kicinski self.space_name = space_name 601be5bea1cSJakub Kicinski self.attr_set = family.attr_sets[space_name] 602be5bea1cSJakub Kicinski # Use list to catch comparisons with empty sets 603be5bea1cSJakub Kicinski self._inherited = inherited if inherited is not None else [] 604be5bea1cSJakub Kicinski self.inherited = [] 605be5bea1cSJakub Kicinski 606be5bea1cSJakub Kicinski self.nested = type_list is None 607be5bea1cSJakub Kicinski if family.name == c_lower(space_name): 608be5bea1cSJakub Kicinski self.render_name = f"{family.name}" 609be5bea1cSJakub Kicinski else: 610be5bea1cSJakub Kicinski self.render_name = f"{family.name}_{c_lower(space_name)}" 611be5bea1cSJakub Kicinski self.struct_name = 'struct ' + self.render_name 6122c9d47a0SJakub Kicinski if self.nested and space_name in family.consts: 6132c9d47a0SJakub Kicinski self.struct_name += '_' 614be5bea1cSJakub Kicinski self.ptr_name = self.struct_name + ' *' 615be5bea1cSJakub Kicinski 616be5bea1cSJakub Kicinski self.request = False 617be5bea1cSJakub Kicinski self.reply = False 618be5bea1cSJakub Kicinski 619be5bea1cSJakub Kicinski self.attr_list = [] 620be5bea1cSJakub Kicinski self.attrs = dict() 6214c8c24e8SJakub Kicinski if type_list is not None: 622be5bea1cSJakub Kicinski for t in type_list: 623be5bea1cSJakub Kicinski self.attr_list.append((t, self.attr_set[t]),) 624be5bea1cSJakub Kicinski else: 625be5bea1cSJakub Kicinski for t in self.attr_set: 626be5bea1cSJakub Kicinski self.attr_list.append((t, self.attr_set[t]),) 627be5bea1cSJakub Kicinski 628be5bea1cSJakub Kicinski max_val = 0 629be5bea1cSJakub Kicinski self.attr_max_val = None 630be5bea1cSJakub Kicinski for name, attr in self.attr_list: 631f7cf6447SJakub Kicinski if attr.value >= max_val: 632be5bea1cSJakub Kicinski max_val = attr.value 633be5bea1cSJakub Kicinski self.attr_max_val = attr 634be5bea1cSJakub Kicinski self.attrs[name] = attr 635be5bea1cSJakub Kicinski 636be5bea1cSJakub Kicinski def __iter__(self): 637be5bea1cSJakub Kicinski yield from self.attrs 638be5bea1cSJakub Kicinski 639be5bea1cSJakub Kicinski def __getitem__(self, key): 640be5bea1cSJakub Kicinski return self.attrs[key] 641be5bea1cSJakub Kicinski 642be5bea1cSJakub Kicinski def member_list(self): 643be5bea1cSJakub Kicinski return self.attr_list 644be5bea1cSJakub Kicinski 645be5bea1cSJakub Kicinski def set_inherited(self, new_inherited): 646be5bea1cSJakub Kicinski if self._inherited != new_inherited: 647be5bea1cSJakub Kicinski raise Exception("Inheriting different members not supported") 648be5bea1cSJakub Kicinski self.inherited = [c_lower(x) for x in sorted(self._inherited)] 649be5bea1cSJakub Kicinski 650be5bea1cSJakub Kicinski 6516517a60bSJakub Kicinskiclass EnumEntry(SpecEnumEntry): 652be5bea1cSJakub Kicinski def __init__(self, enum_set, yaml, prev, value_start): 6536517a60bSJakub Kicinski super().__init__(enum_set, yaml, prev, value_start) 654be5bea1cSJakub Kicinski 655be5bea1cSJakub Kicinski if prev: 656be5bea1cSJakub Kicinski self.value_change = (self.value != prev.value + 1) 657be5bea1cSJakub Kicinski else: 658be5bea1cSJakub Kicinski self.value_change = (self.value != 0) 65966fa34b9SJakub Kicinski self.value_change = self.value_change or self.enum_set['type'] == 'flags' 66066fa34b9SJakub Kicinski 6616517a60bSJakub Kicinski # Added by resolve: 6626517a60bSJakub Kicinski self.c_name = None 6636517a60bSJakub Kicinski delattr(self, "c_name") 664be5bea1cSJakub Kicinski 6656517a60bSJakub Kicinski def resolve(self): 6666517a60bSJakub Kicinski self.resolve_up(super()) 667be5bea1cSJakub Kicinski 6686517a60bSJakub Kicinski self.c_name = c_upper(self.enum_set.value_pfx + self.name) 66966fa34b9SJakub Kicinski 670be5bea1cSJakub Kicinski 6716517a60bSJakub Kicinskiclass EnumSet(SpecEnumSet): 672be5bea1cSJakub Kicinski def __init__(self, family, yaml): 673be5bea1cSJakub Kicinski self.render_name = c_lower(family.name + '-' + yaml['name']) 674dddc9f53SJakub Kicinski 675dddc9f53SJakub Kicinski if 'enum-name' in yaml: 676dddc9f53SJakub Kicinski if yaml['enum-name']: 677dddc9f53SJakub Kicinski self.enum_name = 'enum ' + c_lower(yaml['enum-name']) 678dddc9f53SJakub Kicinski else: 679dddc9f53SJakub Kicinski self.enum_name = None 680dddc9f53SJakub Kicinski else: 681be5bea1cSJakub Kicinski self.enum_name = 'enum ' + self.render_name 682be5bea1cSJakub Kicinski 683be5bea1cSJakub Kicinski self.value_pfx = yaml.get('name-prefix', f"{family.name}-{yaml['name']}-") 684be5bea1cSJakub Kicinski 6856517a60bSJakub Kicinski super().__init__(family, yaml) 686be5bea1cSJakub Kicinski 6876517a60bSJakub Kicinski def new_entry(self, entry, prev_entry, value_start): 6886517a60bSJakub Kicinski return EnumEntry(self, entry, prev_entry, value_start) 689be5bea1cSJakub Kicinski 69010c4d2a7SJakub Kicinski def value_range(self): 69110c4d2a7SJakub Kicinski low = min([x.value for x in self.entries.values()]) 69210c4d2a7SJakub Kicinski high = max([x.value for x in self.entries.values()]) 69310c4d2a7SJakub Kicinski 69410c4d2a7SJakub Kicinski if high - low + 1 != len(self.entries): 69510c4d2a7SJakub Kicinski raise Exception("Can't get value range for a noncontiguous enum") 69610c4d2a7SJakub Kicinski 69710c4d2a7SJakub Kicinski return low, high 69810c4d2a7SJakub Kicinski 699be5bea1cSJakub Kicinski 70030a5c6c8SJakub Kicinskiclass AttrSet(SpecAttrSet): 701be5bea1cSJakub Kicinski def __init__(self, family, yaml): 70230a5c6c8SJakub Kicinski super().__init__(family, yaml) 703be5bea1cSJakub Kicinski 70430a5c6c8SJakub Kicinski if self.subset_of is None: 705be5bea1cSJakub Kicinski if 'name-prefix' in yaml: 706be5bea1cSJakub Kicinski pfx = yaml['name-prefix'] 707be5bea1cSJakub Kicinski elif self.name == family.name: 708be5bea1cSJakub Kicinski pfx = family.name + '-a-' 709be5bea1cSJakub Kicinski else: 710be5bea1cSJakub Kicinski pfx = f"{family.name}-a-{self.name}-" 711be5bea1cSJakub Kicinski self.name_prefix = c_upper(pfx) 712be5bea1cSJakub Kicinski self.max_name = c_upper(self.yaml.get('attr-max-name', f"{self.name_prefix}max")) 713be5bea1cSJakub Kicinski else: 714be5bea1cSJakub Kicinski self.name_prefix = family.attr_sets[self.subset_of].name_prefix 715be5bea1cSJakub Kicinski self.max_name = family.attr_sets[self.subset_of].max_name 716be5bea1cSJakub Kicinski 71730a5c6c8SJakub Kicinski # Added by resolve: 71830a5c6c8SJakub Kicinski self.c_name = None 71930a5c6c8SJakub Kicinski delattr(self, "c_name") 72030a5c6c8SJakub Kicinski 72130a5c6c8SJakub Kicinski def resolve(self): 722be5bea1cSJakub Kicinski self.c_name = c_lower(self.name) 723be5bea1cSJakub Kicinski if self.c_name in _C_KW: 724be5bea1cSJakub Kicinski self.c_name += '_' 72530a5c6c8SJakub Kicinski if self.c_name == self.family.c_name: 726be5bea1cSJakub Kicinski self.c_name = '' 727be5bea1cSJakub Kicinski 72830a5c6c8SJakub Kicinski def new_attr(self, elem, value): 729be093a80SJakub Kicinski if elem['type'] in scalars: 730be093a80SJakub Kicinski t = TypeScalar(self.family, self, elem, value) 731be5bea1cSJakub Kicinski elif elem['type'] == 'unused': 732be093a80SJakub Kicinski t = TypeUnused(self.family, self, elem, value) 733be5bea1cSJakub Kicinski elif elem['type'] == 'pad': 734be093a80SJakub Kicinski t = TypePad(self.family, self, elem, value) 735be5bea1cSJakub Kicinski elif elem['type'] == 'flag': 736be093a80SJakub Kicinski t = TypeFlag(self.family, self, elem, value) 737be5bea1cSJakub Kicinski elif elem['type'] == 'string': 738be093a80SJakub Kicinski t = TypeString(self.family, self, elem, value) 739be5bea1cSJakub Kicinski elif elem['type'] == 'binary': 740be093a80SJakub Kicinski t = TypeBinary(self.family, self, elem, value) 741be5bea1cSJakub Kicinski elif elem['type'] == 'nest': 742be093a80SJakub Kicinski t = TypeNest(self.family, self, elem, value) 743be5bea1cSJakub Kicinski elif elem['type'] == 'array-nest': 744be093a80SJakub Kicinski t = TypeArrayNest(self.family, self, elem, value) 745be5bea1cSJakub Kicinski elif elem['type'] == 'nest-type-value': 746be093a80SJakub Kicinski t = TypeNestTypeValue(self.family, self, elem, value) 747be5bea1cSJakub Kicinski else: 748be5bea1cSJakub Kicinski raise Exception(f"No typed class for type {elem['type']}") 749be5bea1cSJakub Kicinski 750be093a80SJakub Kicinski if 'multi-attr' in elem and elem['multi-attr']: 751be093a80SJakub Kicinski t = TypeMultiAttr(self.family, self, elem, value, t) 752be093a80SJakub Kicinski 753be093a80SJakub Kicinski return t 754be093a80SJakub Kicinski 755be5bea1cSJakub Kicinski 75630a5c6c8SJakub Kicinskiclass Operation(SpecOperation): 75730a5c6c8SJakub Kicinski def __init__(self, family, yaml, req_value, rsp_value): 75830a5c6c8SJakub Kicinski super().__init__(family, yaml, req_value, rsp_value) 759be5bea1cSJakub Kicinski 760be5bea1cSJakub Kicinski self.render_name = family.name + '_' + c_lower(self.name) 761be5bea1cSJakub Kicinski 762be5bea1cSJakub Kicinski self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \ 763be5bea1cSJakub Kicinski ('dump' in yaml and 'request' in yaml['dump']) 764be5bea1cSJakub Kicinski 765ced15688SJakub Kicinski self.has_ntf = False 766ced15688SJakub Kicinski 76730a5c6c8SJakub Kicinski # Added by resolve: 76830a5c6c8SJakub Kicinski self.enum_name = None 76930a5c6c8SJakub Kicinski delattr(self, "enum_name") 770be5bea1cSJakub Kicinski 77130a5c6c8SJakub Kicinski def resolve(self): 77230a5c6c8SJakub Kicinski self.resolve_up(super()) 77330a5c6c8SJakub Kicinski 77430a5c6c8SJakub Kicinski if not self.is_async: 77530a5c6c8SJakub Kicinski self.enum_name = self.family.op_prefix + c_upper(self.name) 77630a5c6c8SJakub Kicinski else: 77730a5c6c8SJakub Kicinski self.enum_name = self.family.async_op_prefix + c_upper(self.name) 778be5bea1cSJakub Kicinski 779ced15688SJakub Kicinski def mark_has_ntf(self): 780ced15688SJakub Kicinski self.has_ntf = True 781be5bea1cSJakub Kicinski 782be5bea1cSJakub Kicinski 78330a5c6c8SJakub Kicinskiclass Family(SpecFamily): 784008bcd68SJakub Kicinski def __init__(self, file_name, exclude_ops): 78530a5c6c8SJakub Kicinski # Added by resolve: 78630a5c6c8SJakub Kicinski self.c_name = None 78730a5c6c8SJakub Kicinski delattr(self, "c_name") 78830a5c6c8SJakub Kicinski self.op_prefix = None 78930a5c6c8SJakub Kicinski delattr(self, "op_prefix") 79030a5c6c8SJakub Kicinski self.async_op_prefix = None 79130a5c6c8SJakub Kicinski delattr(self, "async_op_prefix") 79230a5c6c8SJakub Kicinski self.mcgrps = None 79330a5c6c8SJakub Kicinski delattr(self, "mcgrps") 79430a5c6c8SJakub Kicinski self.consts = None 79530a5c6c8SJakub Kicinski delattr(self, "consts") 79630a5c6c8SJakub Kicinski self.hooks = None 79730a5c6c8SJakub Kicinski delattr(self, "hooks") 798be5bea1cSJakub Kicinski 799008bcd68SJakub Kicinski super().__init__(file_name, exclude_ops=exclude_ops) 800be5bea1cSJakub Kicinski 801be5bea1cSJakub Kicinski self.fam_key = c_upper(self.yaml.get('c-family-name', self.yaml["name"] + '_FAMILY_NAME')) 802be5bea1cSJakub Kicinski self.ver_key = c_upper(self.yaml.get('c-version-name', self.yaml["name"] + '_FAMILY_VERSION')) 803be5bea1cSJakub Kicinski 804be5bea1cSJakub Kicinski if 'definitions' not in self.yaml: 805be5bea1cSJakub Kicinski self.yaml['definitions'] = [] 806be5bea1cSJakub Kicinski 807be5bea1cSJakub Kicinski if 'uapi-header' in self.yaml: 808be5bea1cSJakub Kicinski self.uapi_header = self.yaml['uapi-header'] 809be5bea1cSJakub Kicinski else: 810be5bea1cSJakub Kicinski self.uapi_header = f"linux/{self.name}.h" 81130a5c6c8SJakub Kicinski 81230a5c6c8SJakub Kicinski def resolve(self): 81330a5c6c8SJakub Kicinski self.resolve_up(super()) 81430a5c6c8SJakub Kicinski 81530a5c6c8SJakub Kicinski if self.yaml.get('protocol', 'genetlink') not in {'genetlink', 'genetlink-c', 'genetlink-legacy'}: 81630a5c6c8SJakub Kicinski raise Exception("Codegen only supported for genetlink") 81730a5c6c8SJakub Kicinski 81830a5c6c8SJakub Kicinski self.c_name = c_lower(self.name) 819be5bea1cSJakub Kicinski if 'name-prefix' in self.yaml['operations']: 820be5bea1cSJakub Kicinski self.op_prefix = c_upper(self.yaml['operations']['name-prefix']) 821be5bea1cSJakub Kicinski else: 822be5bea1cSJakub Kicinski self.op_prefix = c_upper(self.yaml['name'] + '-cmd-') 823be5bea1cSJakub Kicinski if 'async-prefix' in self.yaml['operations']: 824be5bea1cSJakub Kicinski self.async_op_prefix = c_upper(self.yaml['operations']['async-prefix']) 825be5bea1cSJakub Kicinski else: 826be5bea1cSJakub Kicinski self.async_op_prefix = self.op_prefix 827be5bea1cSJakub Kicinski 828be5bea1cSJakub Kicinski self.mcgrps = self.yaml.get('mcast-groups', {'list': []}) 829be5bea1cSJakub Kicinski 830be5bea1cSJakub Kicinski self.hooks = dict() 831be5bea1cSJakub Kicinski for when in ['pre', 'post']: 832be5bea1cSJakub Kicinski self.hooks[when] = dict() 833be5bea1cSJakub Kicinski for op_mode in ['do', 'dump']: 834be5bea1cSJakub Kicinski self.hooks[when][op_mode] = dict() 835be5bea1cSJakub Kicinski self.hooks[when][op_mode]['set'] = set() 836be5bea1cSJakub Kicinski self.hooks[when][op_mode]['list'] = [] 837be5bea1cSJakub Kicinski 838be5bea1cSJakub Kicinski # dict space-name -> 'request': set(attrs), 'reply': set(attrs) 839be5bea1cSJakub Kicinski self.root_sets = dict() 840be5bea1cSJakub Kicinski # dict space-name -> set('request', 'reply') 841be5bea1cSJakub Kicinski self.pure_nested_structs = dict() 842be5bea1cSJakub Kicinski 843ced15688SJakub Kicinski self._mark_notify() 844be5bea1cSJakub Kicinski self._mock_up_events() 845be5bea1cSJakub Kicinski 846be5bea1cSJakub Kicinski self._load_root_sets() 847be5bea1cSJakub Kicinski self._load_nested_sets() 848be5bea1cSJakub Kicinski self._load_hooks() 849be5bea1cSJakub Kicinski 850be5bea1cSJakub Kicinski self.kernel_policy = self.yaml.get('kernel-policy', 'split') 851be5bea1cSJakub Kicinski if self.kernel_policy == 'global': 852be5bea1cSJakub Kicinski self._load_global_policy() 853be5bea1cSJakub Kicinski 8546517a60bSJakub Kicinski def new_enum(self, elem): 8556517a60bSJakub Kicinski return EnumSet(self, elem) 8566517a60bSJakub Kicinski 85730a5c6c8SJakub Kicinski def new_attr_set(self, elem): 85830a5c6c8SJakub Kicinski return AttrSet(self, elem) 859be5bea1cSJakub Kicinski 86030a5c6c8SJakub Kicinski def new_operation(self, elem, req_value, rsp_value): 86130a5c6c8SJakub Kicinski return Operation(self, elem, req_value, rsp_value) 862be5bea1cSJakub Kicinski 863ced15688SJakub Kicinski def _mark_notify(self): 864ced15688SJakub Kicinski for op in self.msgs.values(): 865ced15688SJakub Kicinski if 'notify' in op: 866ced15688SJakub Kicinski self.ops[op['notify']].mark_has_ntf() 867ced15688SJakub Kicinski 868be5bea1cSJakub Kicinski # Fake a 'do' equivalent of all events, so that we can render their response parsing 869be5bea1cSJakub Kicinski def _mock_up_events(self): 870be5bea1cSJakub Kicinski for op in self.yaml['operations']['list']: 871be5bea1cSJakub Kicinski if 'event' in op: 872be5bea1cSJakub Kicinski op['do'] = { 873be5bea1cSJakub Kicinski 'reply': { 874be5bea1cSJakub Kicinski 'attributes': op['event']['attributes'] 875be5bea1cSJakub Kicinski } 876be5bea1cSJakub Kicinski } 877be5bea1cSJakub Kicinski 878be5bea1cSJakub Kicinski def _load_root_sets(self): 8796da3424fSJakub Kicinski for op_name, op in self.msgs.items(): 880be5bea1cSJakub Kicinski if 'attribute-set' not in op: 881be5bea1cSJakub Kicinski continue 882be5bea1cSJakub Kicinski 883be5bea1cSJakub Kicinski req_attrs = set() 884be5bea1cSJakub Kicinski rsp_attrs = set() 885be5bea1cSJakub Kicinski for op_mode in ['do', 'dump']: 886be5bea1cSJakub Kicinski if op_mode in op and 'request' in op[op_mode]: 887be5bea1cSJakub Kicinski req_attrs.update(set(op[op_mode]['request']['attributes'])) 888be5bea1cSJakub Kicinski if op_mode in op and 'reply' in op[op_mode]: 889be5bea1cSJakub Kicinski rsp_attrs.update(set(op[op_mode]['reply']['attributes'])) 8906da3424fSJakub Kicinski if 'event' in op: 8916da3424fSJakub Kicinski rsp_attrs.update(set(op['event']['attributes'])) 892be5bea1cSJakub Kicinski 893be5bea1cSJakub Kicinski if op['attribute-set'] not in self.root_sets: 894be5bea1cSJakub Kicinski self.root_sets[op['attribute-set']] = {'request': req_attrs, 'reply': rsp_attrs} 895be5bea1cSJakub Kicinski else: 896be5bea1cSJakub Kicinski self.root_sets[op['attribute-set']]['request'].update(req_attrs) 897be5bea1cSJakub Kicinski self.root_sets[op['attribute-set']]['reply'].update(rsp_attrs) 898be5bea1cSJakub Kicinski 899be5bea1cSJakub Kicinski def _load_nested_sets(self): 900eae7af21SJakub Kicinski attr_set_queue = list(self.root_sets.keys()) 901eae7af21SJakub Kicinski attr_set_seen = set(self.root_sets.keys()) 902eae7af21SJakub Kicinski 903eae7af21SJakub Kicinski while len(attr_set_queue): 904eae7af21SJakub Kicinski a_set = attr_set_queue.pop(0) 905eae7af21SJakub Kicinski for attr, spec in self.attr_sets[a_set].items(): 906eae7af21SJakub Kicinski if 'nested-attributes' not in spec: 907eae7af21SJakub Kicinski continue 908eae7af21SJakub Kicinski 909be5bea1cSJakub Kicinski nested = spec['nested-attributes'] 910eae7af21SJakub Kicinski if nested not in attr_set_seen: 911eae7af21SJakub Kicinski attr_set_queue.append(nested) 912eae7af21SJakub Kicinski attr_set_seen.add(nested) 913eae7af21SJakub Kicinski 914eae7af21SJakub Kicinski inherit = set() 915be5bea1cSJakub Kicinski if nested not in self.root_sets: 91667c65ce7SJakub Kicinski if nested not in self.pure_nested_structs: 917be5bea1cSJakub Kicinski self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit) 918eae7af21SJakub Kicinski else: 919eae7af21SJakub Kicinski raise Exception(f'Using attr set as root and nested not supported - {nested}') 920be5bea1cSJakub Kicinski 921be5bea1cSJakub Kicinski if 'type-value' in spec: 922be5bea1cSJakub Kicinski if nested in self.root_sets: 923be5bea1cSJakub Kicinski raise Exception("Inheriting members to a space used as root not supported") 924be5bea1cSJakub Kicinski inherit.update(set(spec['type-value'])) 925be5bea1cSJakub Kicinski elif spec['type'] == 'array-nest': 926be5bea1cSJakub Kicinski inherit.add('idx') 927be5bea1cSJakub Kicinski self.pure_nested_structs[nested].set_inherited(inherit) 928be5bea1cSJakub Kicinski 929eae7af21SJakub Kicinski for root_set, rs_members in self.root_sets.items(): 930eae7af21SJakub Kicinski for attr, spec in self.attr_sets[root_set].items(): 931eae7af21SJakub Kicinski if 'nested-attributes' in spec: 932eae7af21SJakub Kicinski nested = spec['nested-attributes'] 933eae7af21SJakub Kicinski if attr in rs_members['request']: 934eae7af21SJakub Kicinski self.pure_nested_structs[nested].request = True 935eae7af21SJakub Kicinski if attr in rs_members['reply']: 936eae7af21SJakub Kicinski self.pure_nested_structs[nested].reply = True 937eae7af21SJakub Kicinski 9386afaa0efSJakub Kicinski # Try to reorder according to dependencies 9396afaa0efSJakub Kicinski pns_key_list = list(self.pure_nested_structs.keys()) 9406afaa0efSJakub Kicinski pns_key_seen = set() 9416afaa0efSJakub Kicinski rounds = len(pns_key_list)**2 # it's basically bubble sort 9426afaa0efSJakub Kicinski for _ in range(rounds): 9436afaa0efSJakub Kicinski if len(pns_key_list) == 0: 9446afaa0efSJakub Kicinski break 9456afaa0efSJakub Kicinski name = pns_key_list.pop(0) 9466afaa0efSJakub Kicinski finished = True 9476afaa0efSJakub Kicinski for _, spec in self.attr_sets[name].items(): 9486afaa0efSJakub Kicinski if 'nested-attributes' in spec: 9496afaa0efSJakub Kicinski if spec['nested-attributes'] not in pns_key_seen: 9506afaa0efSJakub Kicinski # Dicts are sorted, this will make struct last 9516afaa0efSJakub Kicinski struct = self.pure_nested_structs.pop(name) 9526afaa0efSJakub Kicinski self.pure_nested_structs[name] = struct 9536afaa0efSJakub Kicinski finished = False 9546afaa0efSJakub Kicinski break 9556afaa0efSJakub Kicinski if finished: 9566afaa0efSJakub Kicinski pns_key_seen.add(name) 9576afaa0efSJakub Kicinski else: 9586afaa0efSJakub Kicinski pns_key_list.append(name) 95937487f93SJakub Kicinski # Propagate the request / reply 96037487f93SJakub Kicinski for attr_set, struct in reversed(self.pure_nested_structs.items()): 96137487f93SJakub Kicinski for _, spec in self.attr_sets[attr_set].items(): 96237487f93SJakub Kicinski if 'nested-attributes' in spec: 96337487f93SJakub Kicinski child = self.pure_nested_structs.get(spec['nested-attributes']) 96437487f93SJakub Kicinski if child: 96537487f93SJakub Kicinski child.request |= struct.request 96637487f93SJakub Kicinski child.reply |= struct.reply 9676afaa0efSJakub Kicinski 968be5bea1cSJakub Kicinski def _load_global_policy(self): 969be5bea1cSJakub Kicinski global_set = set() 970be5bea1cSJakub Kicinski attr_set_name = None 971be5bea1cSJakub Kicinski for op_name, op in self.ops.items(): 972be5bea1cSJakub Kicinski if not op: 973be5bea1cSJakub Kicinski continue 974be5bea1cSJakub Kicinski if 'attribute-set' not in op: 975be5bea1cSJakub Kicinski continue 976be5bea1cSJakub Kicinski 977be5bea1cSJakub Kicinski if attr_set_name is None: 978be5bea1cSJakub Kicinski attr_set_name = op['attribute-set'] 979be5bea1cSJakub Kicinski if attr_set_name != op['attribute-set']: 980be5bea1cSJakub Kicinski raise Exception('For a global policy all ops must use the same set') 981be5bea1cSJakub Kicinski 982eaf317e7SJakub Kicinski for op_mode in ['do', 'dump']: 983be5bea1cSJakub Kicinski if op_mode in op: 984dc2ef94dSJakub Kicinski req = op[op_mode].get('request') 985dc2ef94dSJakub Kicinski if req: 986dc2ef94dSJakub Kicinski global_set.update(req.get('attributes', [])) 987be5bea1cSJakub Kicinski 988be5bea1cSJakub Kicinski self.global_policy = [] 989be5bea1cSJakub Kicinski self.global_policy_set = attr_set_name 990be5bea1cSJakub Kicinski for attr in self.attr_sets[attr_set_name]: 991be5bea1cSJakub Kicinski if attr in global_set: 992be5bea1cSJakub Kicinski self.global_policy.append(attr) 993be5bea1cSJakub Kicinski 994be5bea1cSJakub Kicinski def _load_hooks(self): 995be5bea1cSJakub Kicinski for op in self.ops.values(): 996be5bea1cSJakub Kicinski for op_mode in ['do', 'dump']: 997be5bea1cSJakub Kicinski if op_mode not in op: 998be5bea1cSJakub Kicinski continue 999be5bea1cSJakub Kicinski for when in ['pre', 'post']: 1000be5bea1cSJakub Kicinski if when not in op[op_mode]: 1001be5bea1cSJakub Kicinski continue 1002be5bea1cSJakub Kicinski name = op[op_mode][when] 1003be5bea1cSJakub Kicinski if name in self.hooks[when][op_mode]['set']: 1004be5bea1cSJakub Kicinski continue 1005be5bea1cSJakub Kicinski self.hooks[when][op_mode]['set'].add(name) 1006be5bea1cSJakub Kicinski self.hooks[when][op_mode]['list'].append(name) 1007be5bea1cSJakub Kicinski 1008be5bea1cSJakub Kicinski 1009be5bea1cSJakub Kicinskiclass RenderInfo: 10106f96ec73SJakub Kicinski def __init__(self, cw, family, ku_space, op, op_mode, attr_set=None): 1011be5bea1cSJakub Kicinski self.family = family 1012be5bea1cSJakub Kicinski self.nl = cw.nlib 1013be5bea1cSJakub Kicinski self.ku_space = ku_space 1014ced15688SJakub Kicinski self.op_mode = op_mode 1015be5bea1cSJakub Kicinski self.op = op 1016be5bea1cSJakub Kicinski 1017be5bea1cSJakub Kicinski # 'do' and 'dump' response parsing is identical 1018be5bea1cSJakub Kicinski self.type_consistent = True 10195605f102SJakub Kicinski if op_mode != 'do' and 'dump' in op and 'do' in op: 10205605f102SJakub Kicinski if ('reply' in op['do']) != ('reply' in op["dump"]): 10215605f102SJakub Kicinski self.type_consistent = False 10225605f102SJakub Kicinski elif 'reply' in op['do'] and op["do"]["reply"] != op["dump"]["reply"]: 10235605f102SJakub Kicinski self.type_consistent = False 1024be5bea1cSJakub Kicinski 1025be5bea1cSJakub Kicinski self.attr_set = attr_set 1026be5bea1cSJakub Kicinski if not self.attr_set: 1027be5bea1cSJakub Kicinski self.attr_set = op['attribute-set'] 1028be5bea1cSJakub Kicinski 10292c9d47a0SJakub Kicinski self.type_name_conflict = False 1030be5bea1cSJakub Kicinski if op: 10316f96ec73SJakub Kicinski self.type_name = c_lower(op.name) 1032be5bea1cSJakub Kicinski else: 1033be5bea1cSJakub Kicinski self.type_name = c_lower(attr_set) 10342c9d47a0SJakub Kicinski if attr_set in family.consts: 10352c9d47a0SJakub Kicinski self.type_name_conflict = True 1036be5bea1cSJakub Kicinski 1037be5bea1cSJakub Kicinski self.cw = cw 1038be5bea1cSJakub Kicinski 1039be5bea1cSJakub Kicinski self.struct = dict() 1040ced15688SJakub Kicinski if op_mode == 'notify': 1041ced15688SJakub Kicinski op_mode = 'do' 1042be5bea1cSJakub Kicinski for op_dir in ['request', 'reply']: 1043be5bea1cSJakub Kicinski if op and op_dir in op[op_mode]: 1044be5bea1cSJakub Kicinski self.struct[op_dir] = Struct(family, self.attr_set, 1045be5bea1cSJakub Kicinski type_list=op[op_mode][op_dir]['attributes']) 1046be5bea1cSJakub Kicinski if op_mode == 'event': 1047be5bea1cSJakub Kicinski self.struct['reply'] = Struct(family, self.attr_set, type_list=op['event']['attributes']) 1048be5bea1cSJakub Kicinski 1049be5bea1cSJakub Kicinski 1050be5bea1cSJakub Kicinskiclass CodeWriter: 1051a02430c0SJakub Kicinski def __init__(self, nlib, out_file=None): 1052be5bea1cSJakub Kicinski self.nlib = nlib 1053be5bea1cSJakub Kicinski 1054be5bea1cSJakub Kicinski self._nl = False 10552c0f1466SJakub Kicinski self._block_end = False 1056be5bea1cSJakub Kicinski self._silent_block = False 1057be5bea1cSJakub Kicinski self._ind = 0 1058a02430c0SJakub Kicinski if out_file is None: 1059a02430c0SJakub Kicinski self._out = os.sys.stdout 1060a02430c0SJakub Kicinski else: 1061a02430c0SJakub Kicinski self._out = tempfile.TemporaryFile('w+') 1062a02430c0SJakub Kicinski self._out_file = out_file 1063a02430c0SJakub Kicinski 1064a02430c0SJakub Kicinski def __del__(self): 1065a02430c0SJakub Kicinski self.close_out_file() 1066a02430c0SJakub Kicinski 1067a02430c0SJakub Kicinski def close_out_file(self): 1068a02430c0SJakub Kicinski if self._out == os.sys.stdout: 1069a02430c0SJakub Kicinski return 1070a02430c0SJakub Kicinski with open(self._out_file, 'w+') as out_file: 1071a02430c0SJakub Kicinski self._out.seek(0) 1072a02430c0SJakub Kicinski shutil.copyfileobj(self._out, out_file) 1073a02430c0SJakub Kicinski self._out.close() 1074a02430c0SJakub Kicinski self._out = os.sys.stdout 1075be5bea1cSJakub Kicinski 1076be5bea1cSJakub Kicinski @classmethod 1077be5bea1cSJakub Kicinski def _is_cond(cls, line): 1078be5bea1cSJakub Kicinski return line.startswith('if') or line.startswith('while') or line.startswith('for') 1079be5bea1cSJakub Kicinski 10802c0f1466SJakub Kicinski def p(self, line, add_ind=0): 10812c0f1466SJakub Kicinski if self._block_end: 10822c0f1466SJakub Kicinski self._block_end = False 10832c0f1466SJakub Kicinski if line.startswith('else'): 10842c0f1466SJakub Kicinski line = '} ' + line 10852c0f1466SJakub Kicinski else: 10862c0f1466SJakub Kicinski self._out.write('\t' * self._ind + '}\n') 10872c0f1466SJakub Kicinski 1088be5bea1cSJakub Kicinski if self._nl: 1089be5bea1cSJakub Kicinski self._out.write('\n') 1090be5bea1cSJakub Kicinski self._nl = False 10912c0f1466SJakub Kicinski 1092be5bea1cSJakub Kicinski ind = self._ind 1093be5bea1cSJakub Kicinski if line[-1] == ':': 1094be5bea1cSJakub Kicinski ind -= 1 1095be5bea1cSJakub Kicinski if self._silent_block: 1096be5bea1cSJakub Kicinski ind += 1 1097be5bea1cSJakub Kicinski self._silent_block = line.endswith(')') and CodeWriter._is_cond(line) 1098be5bea1cSJakub Kicinski if add_ind: 1099be5bea1cSJakub Kicinski ind += add_ind 1100be5bea1cSJakub Kicinski self._out.write('\t' * ind + line + '\n') 1101be5bea1cSJakub Kicinski 1102be5bea1cSJakub Kicinski def nl(self): 1103be5bea1cSJakub Kicinski self._nl = True 1104be5bea1cSJakub Kicinski 1105be5bea1cSJakub Kicinski def block_start(self, line=''): 1106be5bea1cSJakub Kicinski if line: 1107be5bea1cSJakub Kicinski line = line + ' ' 1108be5bea1cSJakub Kicinski self.p(line + '{') 1109be5bea1cSJakub Kicinski self._ind += 1 1110be5bea1cSJakub Kicinski 1111be5bea1cSJakub Kicinski def block_end(self, line=''): 1112be5bea1cSJakub Kicinski if line and line[0] not in {';', ','}: 1113be5bea1cSJakub Kicinski line = ' ' + line 1114be5bea1cSJakub Kicinski self._ind -= 1 11152c0f1466SJakub Kicinski self._nl = False 11162c0f1466SJakub Kicinski if not line: 11172c0f1466SJakub Kicinski # Delay printing closing bracket in case "else" comes next 11182c0f1466SJakub Kicinski if self._block_end: 11192c0f1466SJakub Kicinski self._out.write('\t' * (self._ind + 1) + '}\n') 11202c0f1466SJakub Kicinski self._block_end = True 11212c0f1466SJakub Kicinski else: 11222c0f1466SJakub Kicinski self.p('}' + line) 1123be5bea1cSJakub Kicinski 1124be5bea1cSJakub Kicinski def write_doc_line(self, doc, indent=True): 1125be5bea1cSJakub Kicinski words = doc.split() 1126be5bea1cSJakub Kicinski line = ' *' 1127be5bea1cSJakub Kicinski for word in words: 1128be5bea1cSJakub Kicinski if len(line) + len(word) >= 79: 1129be5bea1cSJakub Kicinski self.p(line) 1130be5bea1cSJakub Kicinski line = ' *' 1131be5bea1cSJakub Kicinski if indent: 1132be5bea1cSJakub Kicinski line += ' ' 1133be5bea1cSJakub Kicinski line += ' ' + word 1134be5bea1cSJakub Kicinski self.p(line) 1135be5bea1cSJakub Kicinski 1136be5bea1cSJakub Kicinski def write_func_prot(self, qual_ret, name, args=None, doc=None, suffix=''): 1137be5bea1cSJakub Kicinski if not args: 1138be5bea1cSJakub Kicinski args = ['void'] 1139be5bea1cSJakub Kicinski 1140be5bea1cSJakub Kicinski if doc: 1141be5bea1cSJakub Kicinski self.p('/*') 1142be5bea1cSJakub Kicinski self.p(' * ' + doc) 1143be5bea1cSJakub Kicinski self.p(' */') 1144be5bea1cSJakub Kicinski 1145be5bea1cSJakub Kicinski oneline = qual_ret 1146be5bea1cSJakub Kicinski if qual_ret[-1] != '*': 1147be5bea1cSJakub Kicinski oneline += ' ' 1148be5bea1cSJakub Kicinski oneline += f"{name}({', '.join(args)}){suffix}" 1149be5bea1cSJakub Kicinski 1150be5bea1cSJakub Kicinski if len(oneline) < 80: 1151be5bea1cSJakub Kicinski self.p(oneline) 1152be5bea1cSJakub Kicinski return 1153be5bea1cSJakub Kicinski 1154be5bea1cSJakub Kicinski v = qual_ret 1155be5bea1cSJakub Kicinski if len(v) > 3: 1156be5bea1cSJakub Kicinski self.p(v) 1157be5bea1cSJakub Kicinski v = '' 1158be5bea1cSJakub Kicinski elif qual_ret[-1] != '*': 1159be5bea1cSJakub Kicinski v += ' ' 1160be5bea1cSJakub Kicinski v += name + '(' 1161be5bea1cSJakub Kicinski ind = '\t' * (len(v) // 8) + ' ' * (len(v) % 8) 1162be5bea1cSJakub Kicinski delta_ind = len(v) - len(ind) 1163be5bea1cSJakub Kicinski v += args[0] 1164be5bea1cSJakub Kicinski i = 1 1165be5bea1cSJakub Kicinski while i < len(args): 1166be5bea1cSJakub Kicinski next_len = len(v) + len(args[i]) 1167be5bea1cSJakub Kicinski if v[0] == '\t': 1168be5bea1cSJakub Kicinski next_len += delta_ind 1169be5bea1cSJakub Kicinski if next_len > 76: 1170be5bea1cSJakub Kicinski self.p(v + ',') 1171be5bea1cSJakub Kicinski v = ind 1172be5bea1cSJakub Kicinski else: 1173be5bea1cSJakub Kicinski v += ', ' 1174be5bea1cSJakub Kicinski v += args[i] 1175be5bea1cSJakub Kicinski i += 1 1176be5bea1cSJakub Kicinski self.p(v + ')' + suffix) 1177be5bea1cSJakub Kicinski 1178be5bea1cSJakub Kicinski def write_func_lvar(self, local_vars): 1179be5bea1cSJakub Kicinski if not local_vars: 1180be5bea1cSJakub Kicinski return 1181be5bea1cSJakub Kicinski 1182be5bea1cSJakub Kicinski if type(local_vars) is str: 1183be5bea1cSJakub Kicinski local_vars = [local_vars] 1184be5bea1cSJakub Kicinski 1185be5bea1cSJakub Kicinski local_vars.sort(key=len, reverse=True) 1186be5bea1cSJakub Kicinski for var in local_vars: 1187be5bea1cSJakub Kicinski self.p(var) 1188be5bea1cSJakub Kicinski self.nl() 1189be5bea1cSJakub Kicinski 1190be5bea1cSJakub Kicinski def write_func(self, qual_ret, name, body, args=None, local_vars=None): 1191be5bea1cSJakub Kicinski self.write_func_prot(qual_ret=qual_ret, name=name, args=args) 1192be5bea1cSJakub Kicinski self.write_func_lvar(local_vars=local_vars) 1193be5bea1cSJakub Kicinski 1194be5bea1cSJakub Kicinski self.block_start() 1195be5bea1cSJakub Kicinski for line in body: 1196be5bea1cSJakub Kicinski self.p(line) 1197be5bea1cSJakub Kicinski self.block_end() 1198be5bea1cSJakub Kicinski 1199be5bea1cSJakub Kicinski def writes_defines(self, defines): 1200be5bea1cSJakub Kicinski longest = 0 1201be5bea1cSJakub Kicinski for define in defines: 1202be5bea1cSJakub Kicinski if len(define[0]) > longest: 1203be5bea1cSJakub Kicinski longest = len(define[0]) 1204be5bea1cSJakub Kicinski longest = ((longest + 8) // 8) * 8 1205be5bea1cSJakub Kicinski for define in defines: 1206be5bea1cSJakub Kicinski line = '#define ' + define[0] 1207be5bea1cSJakub Kicinski line += '\t' * ((longest - len(define[0]) + 7) // 8) 1208be5bea1cSJakub Kicinski if type(define[1]) is int: 1209be5bea1cSJakub Kicinski line += str(define[1]) 1210be5bea1cSJakub Kicinski elif type(define[1]) is str: 1211be5bea1cSJakub Kicinski line += '"' + define[1] + '"' 1212be5bea1cSJakub Kicinski self.p(line) 1213be5bea1cSJakub Kicinski 1214be5bea1cSJakub Kicinski def write_struct_init(self, members): 1215be5bea1cSJakub Kicinski longest = max([len(x[0]) for x in members]) 1216be5bea1cSJakub Kicinski longest += 1 # because we prepend a . 1217be5bea1cSJakub Kicinski longest = ((longest + 8) // 8) * 8 1218be5bea1cSJakub Kicinski for one in members: 1219be5bea1cSJakub Kicinski line = '.' + one[0] 1220be5bea1cSJakub Kicinski line += '\t' * ((longest - len(one[0]) - 1 + 7) // 8) 1221be5bea1cSJakub Kicinski line += '= ' + one[1] + ',' 1222be5bea1cSJakub Kicinski self.p(line) 1223be5bea1cSJakub Kicinski 1224be5bea1cSJakub Kicinski 1225be5bea1cSJakub Kicinskiscalars = {'u8', 'u16', 'u32', 'u64', 's32', 's64'} 1226be5bea1cSJakub Kicinski 1227be5bea1cSJakub Kicinskidirection_to_suffix = { 1228be5bea1cSJakub Kicinski 'reply': '_rsp', 1229be5bea1cSJakub Kicinski 'request': '_req', 1230be5bea1cSJakub Kicinski '': '' 1231be5bea1cSJakub Kicinski} 1232be5bea1cSJakub Kicinski 1233be5bea1cSJakub Kicinskiop_mode_to_wrapper = { 1234be5bea1cSJakub Kicinski 'do': '', 1235be5bea1cSJakub Kicinski 'dump': '_list', 1236be5bea1cSJakub Kicinski 'notify': '_ntf', 1237be5bea1cSJakub Kicinski 'event': '', 1238be5bea1cSJakub Kicinski} 1239be5bea1cSJakub Kicinski 1240be5bea1cSJakub Kicinski_C_KW = { 1241820343ccSJakub Kicinski 'auto', 1242820343ccSJakub Kicinski 'bool', 1243820343ccSJakub Kicinski 'break', 1244820343ccSJakub Kicinski 'case', 1245820343ccSJakub Kicinski 'char', 1246820343ccSJakub Kicinski 'const', 1247820343ccSJakub Kicinski 'continue', 1248820343ccSJakub Kicinski 'default', 1249820343ccSJakub Kicinski 'do', 1250820343ccSJakub Kicinski 'double', 1251820343ccSJakub Kicinski 'else', 1252820343ccSJakub Kicinski 'enum', 1253820343ccSJakub Kicinski 'extern', 1254820343ccSJakub Kicinski 'float', 1255820343ccSJakub Kicinski 'for', 1256820343ccSJakub Kicinski 'goto', 1257820343ccSJakub Kicinski 'if', 1258820343ccSJakub Kicinski 'inline', 1259820343ccSJakub Kicinski 'int', 1260820343ccSJakub Kicinski 'long', 1261820343ccSJakub Kicinski 'register', 1262820343ccSJakub Kicinski 'return', 1263820343ccSJakub Kicinski 'short', 1264820343ccSJakub Kicinski 'signed', 1265820343ccSJakub Kicinski 'sizeof', 1266820343ccSJakub Kicinski 'static', 1267820343ccSJakub Kicinski 'struct', 1268820343ccSJakub Kicinski 'switch', 1269820343ccSJakub Kicinski 'typedef', 1270820343ccSJakub Kicinski 'union', 1271820343ccSJakub Kicinski 'unsigned', 1272820343ccSJakub Kicinski 'void', 1273820343ccSJakub Kicinski 'volatile', 1274820343ccSJakub Kicinski 'while' 1275be5bea1cSJakub Kicinski} 1276be5bea1cSJakub Kicinski 1277be5bea1cSJakub Kicinski 1278be5bea1cSJakub Kicinskidef rdir(direction): 1279be5bea1cSJakub Kicinski if direction == 'reply': 1280be5bea1cSJakub Kicinski return 'request' 1281be5bea1cSJakub Kicinski if direction == 'request': 1282be5bea1cSJakub Kicinski return 'reply' 1283be5bea1cSJakub Kicinski return direction 1284be5bea1cSJakub Kicinski 1285be5bea1cSJakub Kicinski 1286be5bea1cSJakub Kicinskidef op_prefix(ri, direction, deref=False): 1287be5bea1cSJakub Kicinski suffix = f"_{ri.type_name}" 1288be5bea1cSJakub Kicinski 1289be5bea1cSJakub Kicinski if not ri.op_mode or ri.op_mode == 'do': 1290be5bea1cSJakub Kicinski suffix += f"{direction_to_suffix[direction]}" 1291be5bea1cSJakub Kicinski else: 1292be5bea1cSJakub Kicinski if direction == 'request': 1293be5bea1cSJakub Kicinski suffix += '_req_dump' 1294be5bea1cSJakub Kicinski else: 1295be5bea1cSJakub Kicinski if ri.type_consistent: 1296be5bea1cSJakub Kicinski if deref: 1297be5bea1cSJakub Kicinski suffix += f"{direction_to_suffix[direction]}" 1298be5bea1cSJakub Kicinski else: 1299be5bea1cSJakub Kicinski suffix += op_mode_to_wrapper[ri.op_mode] 1300be5bea1cSJakub Kicinski else: 1301be5bea1cSJakub Kicinski suffix += '_rsp' 1302be5bea1cSJakub Kicinski suffix += '_dump' if deref else '_list' 1303be5bea1cSJakub Kicinski 1304be5bea1cSJakub Kicinski return f"{ri.family['name']}{suffix}" 1305be5bea1cSJakub Kicinski 1306be5bea1cSJakub Kicinski 1307be5bea1cSJakub Kicinskidef type_name(ri, direction, deref=False): 1308be5bea1cSJakub Kicinski return f"struct {op_prefix(ri, direction, deref=deref)}" 1309be5bea1cSJakub Kicinski 1310be5bea1cSJakub Kicinski 1311be5bea1cSJakub Kicinskidef print_prototype(ri, direction, terminate=True, doc=None): 1312be5bea1cSJakub Kicinski suffix = ';' if terminate else '' 1313be5bea1cSJakub Kicinski 1314be5bea1cSJakub Kicinski fname = ri.op.render_name 1315be5bea1cSJakub Kicinski if ri.op_mode == 'dump': 1316be5bea1cSJakub Kicinski fname += '_dump' 1317be5bea1cSJakub Kicinski 1318be5bea1cSJakub Kicinski args = ['struct ynl_sock *ys'] 1319be5bea1cSJakub Kicinski if 'request' in ri.op[ri.op_mode]: 1320be5bea1cSJakub Kicinski args.append(f"{type_name(ri, direction)} *" + f"{direction_to_suffix[direction][1:]}") 1321be5bea1cSJakub Kicinski 1322be5bea1cSJakub Kicinski ret = 'int' 1323be5bea1cSJakub Kicinski if 'reply' in ri.op[ri.op_mode]: 1324be5bea1cSJakub Kicinski ret = f"{type_name(ri, rdir(direction))} *" 1325be5bea1cSJakub Kicinski 1326be5bea1cSJakub Kicinski ri.cw.write_func_prot(ret, fname, args, doc=doc, suffix=suffix) 1327be5bea1cSJakub Kicinski 1328be5bea1cSJakub Kicinski 1329be5bea1cSJakub Kicinskidef print_req_prototype(ri): 1330be5bea1cSJakub Kicinski print_prototype(ri, "request", doc=ri.op['doc']) 1331be5bea1cSJakub Kicinski 1332be5bea1cSJakub Kicinski 1333be5bea1cSJakub Kicinskidef print_dump_prototype(ri): 1334be5bea1cSJakub Kicinski print_prototype(ri, "request") 1335be5bea1cSJakub Kicinski 1336be5bea1cSJakub Kicinski 1337be5bea1cSJakub Kicinskidef put_typol(cw, struct): 1338be5bea1cSJakub Kicinski type_max = struct.attr_set.max_name 1339be5bea1cSJakub Kicinski cw.block_start(line=f'struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =') 1340be5bea1cSJakub Kicinski 1341be5bea1cSJakub Kicinski for _, arg in struct.member_list(): 1342be5bea1cSJakub Kicinski arg.attr_typol(cw) 1343be5bea1cSJakub Kicinski 1344be5bea1cSJakub Kicinski cw.block_end(line=';') 1345be5bea1cSJakub Kicinski cw.nl() 1346be5bea1cSJakub Kicinski 1347be5bea1cSJakub Kicinski cw.block_start(line=f'struct ynl_policy_nest {struct.render_name}_nest =') 1348be5bea1cSJakub Kicinski cw.p(f'.max_attr = {type_max},') 1349be5bea1cSJakub Kicinski cw.p(f'.table = {struct.render_name}_policy,') 1350be5bea1cSJakub Kicinski cw.block_end(line=';') 1351be5bea1cSJakub Kicinski cw.nl() 1352be5bea1cSJakub Kicinski 1353be5bea1cSJakub Kicinski 13546f115d45SJakub Kicinskidef _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None): 13556f115d45SJakub Kicinski args = [f'int {arg_name}'] 13566f115d45SJakub Kicinski if enum and not ('enum-name' in enum and not enum['enum-name']): 13576f115d45SJakub Kicinski args = [f'enum {render_name} {arg_name}'] 13586f115d45SJakub Kicinski cw.write_func_prot('const char *', f'{render_name}_str', args) 13596f115d45SJakub Kicinski cw.block_start() 13606f115d45SJakub Kicinski if enum and enum.type == 'flags': 13616f115d45SJakub Kicinski cw.p(f'{arg_name} = ffs({arg_name}) - 1;') 13626f115d45SJakub Kicinski cw.p(f'if ({arg_name} < 0 || {arg_name} >= (int)MNL_ARRAY_SIZE({map_name}))') 13636f115d45SJakub Kicinski cw.p('return NULL;') 13646f115d45SJakub Kicinski cw.p(f'return {map_name}[{arg_name}];') 13656f115d45SJakub Kicinski cw.block_end() 13666f115d45SJakub Kicinski cw.nl() 13676f115d45SJakub Kicinski 13686f115d45SJakub Kicinski 136921b6e302SJakub Kicinskidef put_op_name_fwd(family, cw): 137021b6e302SJakub Kicinski cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op'], suffix=';') 137121b6e302SJakub Kicinski 137221b6e302SJakub Kicinski 137321b6e302SJakub Kicinskidef put_op_name(family, cw): 137421b6e302SJakub Kicinski map_name = f'{family.name}_op_strmap' 137521b6e302SJakub Kicinski cw.block_start(line=f"static const char * const {map_name}[] =") 137621b6e302SJakub Kicinski for op_name, op in family.msgs.items(): 13779858bfc2SJakub Kicinski if op.rsp_value: 13789858bfc2SJakub Kicinski if op.req_value == op.rsp_value: 137921b6e302SJakub Kicinski cw.p(f'[{op.enum_name}] = "{op_name}",') 13809858bfc2SJakub Kicinski else: 13819858bfc2SJakub Kicinski cw.p(f'[{op.rsp_value}] = "{op_name}",') 138221b6e302SJakub Kicinski cw.block_end(line=';') 138321b6e302SJakub Kicinski cw.nl() 138421b6e302SJakub Kicinski 13856f115d45SJakub Kicinski _put_enum_to_str_helper(cw, family.name + '_op', map_name, 'op') 138621b6e302SJakub Kicinski 138721b6e302SJakub Kicinski 138821b6e302SJakub Kicinskidef put_enum_to_str_fwd(family, cw, enum): 138921b6e302SJakub Kicinski args = [f'enum {enum.render_name} value'] 139021b6e302SJakub Kicinski if 'enum-name' in enum and not enum['enum-name']: 139121b6e302SJakub Kicinski args = ['int value'] 139221b6e302SJakub Kicinski cw.write_func_prot('const char *', f'{enum.render_name}_str', args, suffix=';') 139321b6e302SJakub Kicinski 139421b6e302SJakub Kicinski 139521b6e302SJakub Kicinskidef put_enum_to_str(family, cw, enum): 139621b6e302SJakub Kicinski map_name = f'{enum.render_name}_strmap' 139721b6e302SJakub Kicinski cw.block_start(line=f"static const char * const {map_name}[] =") 139821b6e302SJakub Kicinski for entry in enum.entries.values(): 139921b6e302SJakub Kicinski cw.p(f'[{entry.value}] = "{entry.name}",') 140021b6e302SJakub Kicinski cw.block_end(line=';') 140121b6e302SJakub Kicinski cw.nl() 140221b6e302SJakub Kicinski 14036f115d45SJakub Kicinski _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum) 140421b6e302SJakub Kicinski 140521b6e302SJakub Kicinski 1406be5bea1cSJakub Kicinskidef put_req_nested(ri, struct): 1407be5bea1cSJakub Kicinski func_args = ['struct nlmsghdr *nlh', 1408be5bea1cSJakub Kicinski 'unsigned int attr_type', 1409be5bea1cSJakub Kicinski f'{struct.ptr_name}obj'] 1410be5bea1cSJakub Kicinski 1411be5bea1cSJakub Kicinski ri.cw.write_func_prot('int', f'{struct.render_name}_put', func_args) 1412be5bea1cSJakub Kicinski ri.cw.block_start() 1413be5bea1cSJakub Kicinski ri.cw.write_func_lvar('struct nlattr *nest;') 1414be5bea1cSJakub Kicinski 1415be5bea1cSJakub Kicinski ri.cw.p("nest = mnl_attr_nest_start(nlh, attr_type);") 1416be5bea1cSJakub Kicinski 1417be5bea1cSJakub Kicinski for _, arg in struct.member_list(): 1418be5bea1cSJakub Kicinski arg.attr_put(ri, "obj") 1419be5bea1cSJakub Kicinski 1420be5bea1cSJakub Kicinski ri.cw.p("mnl_attr_nest_end(nlh, nest);") 1421be5bea1cSJakub Kicinski 1422be5bea1cSJakub Kicinski ri.cw.nl() 1423be5bea1cSJakub Kicinski ri.cw.p('return 0;') 1424be5bea1cSJakub Kicinski ri.cw.block_end() 1425be5bea1cSJakub Kicinski ri.cw.nl() 1426be5bea1cSJakub Kicinski 1427be5bea1cSJakub Kicinski 1428be5bea1cSJakub Kicinskidef _multi_parse(ri, struct, init_lines, local_vars): 1429be5bea1cSJakub Kicinski if struct.nested: 1430be5bea1cSJakub Kicinski iter_line = "mnl_attr_for_each_nested(attr, nested)" 1431be5bea1cSJakub Kicinski else: 1432be5bea1cSJakub Kicinski iter_line = "mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr))" 1433be5bea1cSJakub Kicinski 1434be5bea1cSJakub Kicinski array_nests = set() 1435be5bea1cSJakub Kicinski multi_attrs = set() 1436be5bea1cSJakub Kicinski needs_parg = False 1437be5bea1cSJakub Kicinski for arg, aspec in struct.member_list(): 1438be5bea1cSJakub Kicinski if aspec['type'] == 'array-nest': 1439be5bea1cSJakub Kicinski local_vars.append(f'const struct nlattr *attr_{aspec.c_name};') 1440be5bea1cSJakub Kicinski array_nests.add(arg) 1441be5bea1cSJakub Kicinski if 'multi-attr' in aspec: 1442be5bea1cSJakub Kicinski multi_attrs.add(arg) 1443be5bea1cSJakub Kicinski needs_parg |= 'nested-attributes' in aspec 1444be5bea1cSJakub Kicinski if array_nests or multi_attrs: 1445be5bea1cSJakub Kicinski local_vars.append('int i;') 1446be5bea1cSJakub Kicinski if needs_parg: 1447be5bea1cSJakub Kicinski local_vars.append('struct ynl_parse_arg parg;') 1448be5bea1cSJakub Kicinski init_lines.append('parg.ys = yarg->ys;') 1449be5bea1cSJakub Kicinski 145058da455bSJakub Kicinski all_multi = array_nests | multi_attrs 145158da455bSJakub Kicinski 145258da455bSJakub Kicinski for anest in sorted(all_multi): 145358da455bSJakub Kicinski local_vars.append(f"unsigned int n_{struct[anest].c_name} = 0;") 145458da455bSJakub Kicinski 1455be5bea1cSJakub Kicinski ri.cw.block_start() 1456be5bea1cSJakub Kicinski ri.cw.write_func_lvar(local_vars) 1457be5bea1cSJakub Kicinski 1458be5bea1cSJakub Kicinski for line in init_lines: 1459be5bea1cSJakub Kicinski ri.cw.p(line) 1460be5bea1cSJakub Kicinski ri.cw.nl() 1461be5bea1cSJakub Kicinski 1462be5bea1cSJakub Kicinski for arg in struct.inherited: 1463be5bea1cSJakub Kicinski ri.cw.p(f'dst->{arg} = {arg};') 1464be5bea1cSJakub Kicinski 146558da455bSJakub Kicinski for anest in sorted(all_multi): 146658da455bSJakub Kicinski aspec = struct[anest] 146758da455bSJakub Kicinski ri.cw.p(f"if (dst->{aspec.c_name})") 146858da455bSJakub Kicinski ri.cw.p(f'return ynl_error_parse(yarg, "attribute already present ({struct.attr_set.name}.{aspec.name})");') 146958da455bSJakub Kicinski 1470be5bea1cSJakub Kicinski ri.cw.nl() 1471be5bea1cSJakub Kicinski ri.cw.block_start(line=iter_line) 1472e4ea3cc6SJakub Kicinski ri.cw.p('unsigned int type = mnl_attr_get_type(attr);') 1473e4ea3cc6SJakub Kicinski ri.cw.nl() 1474be5bea1cSJakub Kicinski 1475be5bea1cSJakub Kicinski first = True 1476be5bea1cSJakub Kicinski for _, arg in struct.member_list(): 14776ad49839SJakub Kicinski good = arg.attr_get(ri, 'dst', first=first) 14786ad49839SJakub Kicinski # First may be 'unused' or 'pad', ignore those 14796ad49839SJakub Kicinski first &= not good 1480be5bea1cSJakub Kicinski 1481be5bea1cSJakub Kicinski ri.cw.block_end() 1482be5bea1cSJakub Kicinski ri.cw.nl() 1483be5bea1cSJakub Kicinski 1484be5bea1cSJakub Kicinski for anest in sorted(array_nests): 1485be5bea1cSJakub Kicinski aspec = struct[anest] 1486be5bea1cSJakub Kicinski 148758da455bSJakub Kicinski ri.cw.block_start(line=f"if (n_{aspec.c_name})") 148858da455bSJakub Kicinski ri.cw.p(f"dst->{aspec.c_name} = calloc({aspec.c_name}, sizeof(*dst->{aspec.c_name}));") 148958da455bSJakub Kicinski ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};") 1490be5bea1cSJakub Kicinski ri.cw.p('i = 0;') 1491be5bea1cSJakub Kicinski ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;") 1492be5bea1cSJakub Kicinski ri.cw.block_start(line=f"mnl_attr_for_each_nested(attr, attr_{aspec.c_name})") 1493be5bea1cSJakub Kicinski ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];") 1494be5bea1cSJakub Kicinski ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr, mnl_attr_get_type(attr)))") 1495be5bea1cSJakub Kicinski ri.cw.p('return MNL_CB_ERROR;') 1496be5bea1cSJakub Kicinski ri.cw.p('i++;') 1497be5bea1cSJakub Kicinski ri.cw.block_end() 1498be5bea1cSJakub Kicinski ri.cw.block_end() 1499be5bea1cSJakub Kicinski ri.cw.nl() 1500be5bea1cSJakub Kicinski 1501be5bea1cSJakub Kicinski for anest in sorted(multi_attrs): 1502be5bea1cSJakub Kicinski aspec = struct[anest] 150358da455bSJakub Kicinski ri.cw.block_start(line=f"if (n_{aspec.c_name})") 150458da455bSJakub Kicinski ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") 150558da455bSJakub Kicinski ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};") 1506be5bea1cSJakub Kicinski ri.cw.p('i = 0;') 1507be5bea1cSJakub Kicinski if 'nested-attributes' in aspec: 1508be5bea1cSJakub Kicinski ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;") 1509be5bea1cSJakub Kicinski ri.cw.block_start(line=iter_line) 1510be5bea1cSJakub Kicinski ri.cw.block_start(line=f"if (mnl_attr_get_type(attr) == {aspec.enum_name})") 1511be5bea1cSJakub Kicinski if 'nested-attributes' in aspec: 1512be5bea1cSJakub Kicinski ri.cw.p(f"parg.data = &dst->{aspec.c_name}[i];") 1513be5bea1cSJakub Kicinski ri.cw.p(f"if ({aspec.nested_render_name}_parse(&parg, attr))") 1514be5bea1cSJakub Kicinski ri.cw.p('return MNL_CB_ERROR;') 1515be5bea1cSJakub Kicinski elif aspec['type'] in scalars: 1516be5bea1cSJakub Kicinski t = aspec['type'] 1517be5bea1cSJakub Kicinski if t[0] == 's': 1518be5bea1cSJakub Kicinski t = 'u' + t[1:] 1519be5bea1cSJakub Kicinski ri.cw.p(f"dst->{aspec.c_name}[i] = mnl_attr_get_{t}(attr);") 1520be5bea1cSJakub Kicinski else: 1521be5bea1cSJakub Kicinski raise Exception('Nest parsing type not supported yet') 1522be5bea1cSJakub Kicinski ri.cw.p('i++;') 1523be5bea1cSJakub Kicinski ri.cw.block_end() 1524be5bea1cSJakub Kicinski ri.cw.block_end() 1525be5bea1cSJakub Kicinski ri.cw.block_end() 1526be5bea1cSJakub Kicinski ri.cw.nl() 1527be5bea1cSJakub Kicinski 1528be5bea1cSJakub Kicinski if struct.nested: 1529be5bea1cSJakub Kicinski ri.cw.p('return 0;') 1530be5bea1cSJakub Kicinski else: 1531be5bea1cSJakub Kicinski ri.cw.p('return MNL_CB_OK;') 1532be5bea1cSJakub Kicinski ri.cw.block_end() 1533be5bea1cSJakub Kicinski ri.cw.nl() 1534be5bea1cSJakub Kicinski 1535be5bea1cSJakub Kicinski 1536be5bea1cSJakub Kicinskidef parse_rsp_nested(ri, struct): 1537be5bea1cSJakub Kicinski func_args = ['struct ynl_parse_arg *yarg', 1538be5bea1cSJakub Kicinski 'const struct nlattr *nested'] 1539be5bea1cSJakub Kicinski for arg in struct.inherited: 1540be5bea1cSJakub Kicinski func_args.append('__u32 ' + arg) 1541be5bea1cSJakub Kicinski 1542be5bea1cSJakub Kicinski local_vars = ['const struct nlattr *attr;', 1543be5bea1cSJakub Kicinski f'{struct.ptr_name}dst = yarg->data;'] 1544be5bea1cSJakub Kicinski init_lines = [] 1545be5bea1cSJakub Kicinski 1546be5bea1cSJakub Kicinski ri.cw.write_func_prot('int', f'{struct.render_name}_parse', func_args) 1547be5bea1cSJakub Kicinski 1548be5bea1cSJakub Kicinski _multi_parse(ri, struct, init_lines, local_vars) 1549be5bea1cSJakub Kicinski 1550be5bea1cSJakub Kicinski 1551be5bea1cSJakub Kicinskidef parse_rsp_msg(ri, deref=False): 1552be5bea1cSJakub Kicinski if 'reply' not in ri.op[ri.op_mode] and ri.op_mode != 'event': 1553be5bea1cSJakub Kicinski return 1554be5bea1cSJakub Kicinski 1555be5bea1cSJakub Kicinski func_args = ['const struct nlmsghdr *nlh', 1556be5bea1cSJakub Kicinski 'void *data'] 1557be5bea1cSJakub Kicinski 1558be5bea1cSJakub Kicinski local_vars = [f'{type_name(ri, "reply", deref=deref)} *dst;', 1559be5bea1cSJakub Kicinski 'struct ynl_parse_arg *yarg = data;', 1560be5bea1cSJakub Kicinski 'const struct nlattr *attr;'] 1561be5bea1cSJakub Kicinski init_lines = ['dst = yarg->data;'] 1562be5bea1cSJakub Kicinski 1563be5bea1cSJakub Kicinski ri.cw.write_func_prot('int', f'{op_prefix(ri, "reply", deref=deref)}_parse', func_args) 1564be5bea1cSJakub Kicinski 15654c8c24e8SJakub Kicinski if ri.struct["reply"].member_list(): 1566be5bea1cSJakub Kicinski _multi_parse(ri, ri.struct["reply"], init_lines, local_vars) 15674c8c24e8SJakub Kicinski else: 15684c8c24e8SJakub Kicinski # Empty reply 15694c8c24e8SJakub Kicinski ri.cw.block_start() 15704c8c24e8SJakub Kicinski ri.cw.p('return MNL_CB_OK;') 15714c8c24e8SJakub Kicinski ri.cw.block_end() 15724c8c24e8SJakub Kicinski ri.cw.nl() 1573be5bea1cSJakub Kicinski 1574be5bea1cSJakub Kicinski 1575be5bea1cSJakub Kicinskidef print_req(ri): 1576be5bea1cSJakub Kicinski ret_ok = '0' 1577be5bea1cSJakub Kicinski ret_err = '-1' 1578be5bea1cSJakub Kicinski direction = "request" 1579be5bea1cSJakub Kicinski local_vars = ['struct nlmsghdr *nlh;', 1580dc0956c9SJakub Kicinski 'int err;'] 1581be5bea1cSJakub Kicinski 1582be5bea1cSJakub Kicinski if 'reply' in ri.op[ri.op_mode]: 1583be5bea1cSJakub Kicinski ret_ok = 'rsp' 1584be5bea1cSJakub Kicinski ret_err = 'NULL' 1585be5bea1cSJakub Kicinski local_vars += [f'{type_name(ri, rdir(direction))} *rsp;', 1586dc0956c9SJakub Kicinski 'struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };'] 1587be5bea1cSJakub Kicinski 1588be5bea1cSJakub Kicinski print_prototype(ri, direction, terminate=False) 1589be5bea1cSJakub Kicinski ri.cw.block_start() 1590be5bea1cSJakub Kicinski ri.cw.write_func_lvar(local_vars) 1591be5bea1cSJakub Kicinski 1592be5bea1cSJakub Kicinski ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") 1593be5bea1cSJakub Kicinski 1594be5bea1cSJakub Kicinski ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;") 1595be5bea1cSJakub Kicinski if 'reply' in ri.op[ri.op_mode]: 1596dc0956c9SJakub Kicinski ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") 1597be5bea1cSJakub Kicinski ri.cw.nl() 1598be5bea1cSJakub Kicinski for _, attr in ri.struct["request"].member_list(): 1599be5bea1cSJakub Kicinski attr.attr_put(ri, "req") 1600be5bea1cSJakub Kicinski ri.cw.nl() 1601be5bea1cSJakub Kicinski 1602dc0956c9SJakub Kicinski parse_arg = "NULL" 1603be5bea1cSJakub Kicinski if 'reply' in ri.op[ri.op_mode]: 1604be5bea1cSJakub Kicinski ri.cw.p('rsp = calloc(1, sizeof(*rsp));') 1605dc0956c9SJakub Kicinski ri.cw.p('yrs.yarg.data = rsp;') 1606dc0956c9SJakub Kicinski ri.cw.p(f"yrs.cb = {op_prefix(ri, 'reply')}_parse;") 1607dc0956c9SJakub Kicinski if ri.op.value is not None: 1608dc0956c9SJakub Kicinski ri.cw.p(f'yrs.rsp_cmd = {ri.op.enum_name};') 1609dc0956c9SJakub Kicinski else: 1610dc0956c9SJakub Kicinski ri.cw.p(f'yrs.rsp_cmd = {ri.op.rsp_value};') 1611be5bea1cSJakub Kicinski ri.cw.nl() 1612dc0956c9SJakub Kicinski parse_arg = '&yrs' 1613dc0956c9SJakub Kicinski ri.cw.p(f"err = ynl_exec(ys, nlh, {parse_arg});") 1614be5bea1cSJakub Kicinski ri.cw.p('if (err < 0)') 1615dc0956c9SJakub Kicinski if 'reply' in ri.op[ri.op_mode]: 1616be5bea1cSJakub Kicinski ri.cw.p('goto err_free;') 1617dc0956c9SJakub Kicinski else: 1618dc0956c9SJakub Kicinski ri.cw.p('return -1;') 1619be5bea1cSJakub Kicinski ri.cw.nl() 1620be5bea1cSJakub Kicinski 1621be5bea1cSJakub Kicinski ri.cw.p(f"return {ret_ok};") 1622be5bea1cSJakub Kicinski ri.cw.nl() 1623be5bea1cSJakub Kicinski 1624be5bea1cSJakub Kicinski if 'reply' in ri.op[ri.op_mode]: 1625dc0956c9SJakub Kicinski ri.cw.p('err_free:') 1626be5bea1cSJakub Kicinski ri.cw.p(f"{call_free(ri, rdir(direction), 'rsp')}") 1627be5bea1cSJakub Kicinski ri.cw.p(f"return {ret_err};") 1628dc0956c9SJakub Kicinski 1629be5bea1cSJakub Kicinski ri.cw.block_end() 1630be5bea1cSJakub Kicinski 1631be5bea1cSJakub Kicinski 1632be5bea1cSJakub Kicinskidef print_dump(ri): 1633be5bea1cSJakub Kicinski direction = "request" 1634be5bea1cSJakub Kicinski print_prototype(ri, direction, terminate=False) 1635be5bea1cSJakub Kicinski ri.cw.block_start() 1636be5bea1cSJakub Kicinski local_vars = ['struct ynl_dump_state yds = {};', 1637be5bea1cSJakub Kicinski 'struct nlmsghdr *nlh;', 1638dc0956c9SJakub Kicinski 'int err;'] 1639be5bea1cSJakub Kicinski 1640be5bea1cSJakub Kicinski for var in local_vars: 1641be5bea1cSJakub Kicinski ri.cw.p(f'{var}') 1642be5bea1cSJakub Kicinski ri.cw.nl() 1643be5bea1cSJakub Kicinski 1644be5bea1cSJakub Kicinski ri.cw.p('yds.ys = ys;') 1645be5bea1cSJakub Kicinski ri.cw.p(f"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});") 1646be5bea1cSJakub Kicinski ri.cw.p(f"yds.cb = {op_prefix(ri, 'reply', deref=True)}_parse;") 1647dc0956c9SJakub Kicinski if ri.op.value is not None: 1648dc0956c9SJakub Kicinski ri.cw.p(f'yds.rsp_cmd = {ri.op.enum_name};') 1649dc0956c9SJakub Kicinski else: 1650dc0956c9SJakub Kicinski ri.cw.p(f'yds.rsp_cmd = {ri.op.rsp_value};') 1651be5bea1cSJakub Kicinski ri.cw.p(f"yds.rsp_policy = &{ri.struct['reply'].render_name}_nest;") 1652be5bea1cSJakub Kicinski ri.cw.nl() 1653be5bea1cSJakub Kicinski ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") 1654be5bea1cSJakub Kicinski 1655be5bea1cSJakub Kicinski if "request" in ri.op[ri.op_mode]: 1656be5bea1cSJakub Kicinski ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;") 1657be5bea1cSJakub Kicinski ri.cw.nl() 1658be5bea1cSJakub Kicinski for _, attr in ri.struct["request"].member_list(): 1659be5bea1cSJakub Kicinski attr.attr_put(ri, "req") 1660be5bea1cSJakub Kicinski ri.cw.nl() 1661be5bea1cSJakub Kicinski 1662dc0956c9SJakub Kicinski ri.cw.p('err = ynl_exec_dump(ys, nlh, &yds);') 1663be5bea1cSJakub Kicinski ri.cw.p('if (err < 0)') 1664be5bea1cSJakub Kicinski ri.cw.p('goto free_list;') 1665be5bea1cSJakub Kicinski ri.cw.nl() 1666be5bea1cSJakub Kicinski 1667be5bea1cSJakub Kicinski ri.cw.p('return yds.first;') 1668be5bea1cSJakub Kicinski ri.cw.nl() 1669be5bea1cSJakub Kicinski ri.cw.p('free_list:') 1670be5bea1cSJakub Kicinski ri.cw.p(call_free(ri, rdir(direction), 'yds.first')) 1671be5bea1cSJakub Kicinski ri.cw.p('return NULL;') 1672be5bea1cSJakub Kicinski ri.cw.block_end() 1673be5bea1cSJakub Kicinski 1674be5bea1cSJakub Kicinski 1675be5bea1cSJakub Kicinskidef call_free(ri, direction, var): 1676be5bea1cSJakub Kicinski return f"{op_prefix(ri, direction)}_free({var});" 1677be5bea1cSJakub Kicinski 1678be5bea1cSJakub Kicinski 1679be5bea1cSJakub Kicinskidef free_arg_name(direction): 1680be5bea1cSJakub Kicinski if direction: 1681be5bea1cSJakub Kicinski return direction_to_suffix[direction][1:] 1682be5bea1cSJakub Kicinski return 'obj' 1683be5bea1cSJakub Kicinski 1684be5bea1cSJakub Kicinski 16855d58f911SJakub Kicinskidef print_alloc_wrapper(ri, direction): 16865d58f911SJakub Kicinski name = op_prefix(ri, direction) 16875d58f911SJakub Kicinski ri.cw.write_func_prot(f'static inline struct {name} *', f"{name}_alloc", [f"void"]) 16885d58f911SJakub Kicinski ri.cw.block_start() 16895d58f911SJakub Kicinski ri.cw.p(f'return calloc(1, sizeof(struct {name}));') 16905d58f911SJakub Kicinski ri.cw.block_end() 16915d58f911SJakub Kicinski 16925d58f911SJakub Kicinski 1693be5bea1cSJakub Kicinskidef print_free_prototype(ri, direction, suffix=';'): 1694be5bea1cSJakub Kicinski name = op_prefix(ri, direction) 16952c9d47a0SJakub Kicinski struct_name = name 16962c9d47a0SJakub Kicinski if ri.type_name_conflict: 16972c9d47a0SJakub Kicinski struct_name += '_' 1698be5bea1cSJakub Kicinski arg = free_arg_name(direction) 16992c9d47a0SJakub Kicinski ri.cw.write_func_prot('void', f"{name}_free", [f"struct {struct_name} *{arg}"], suffix=suffix) 1700be5bea1cSJakub Kicinski 1701be5bea1cSJakub Kicinski 1702be5bea1cSJakub Kicinskidef _print_type(ri, direction, struct): 1703be5bea1cSJakub Kicinski suffix = f'_{ri.type_name}{direction_to_suffix[direction]}' 17042c9d47a0SJakub Kicinski if not direction and ri.type_name_conflict: 17052c9d47a0SJakub Kicinski suffix += '_' 1706be5bea1cSJakub Kicinski 1707be5bea1cSJakub Kicinski if ri.op_mode == 'dump': 1708be5bea1cSJakub Kicinski suffix += '_dump' 1709be5bea1cSJakub Kicinski 1710be5bea1cSJakub Kicinski ri.cw.block_start(line=f"struct {ri.family['name']}{suffix}") 1711be5bea1cSJakub Kicinski 1712be5bea1cSJakub Kicinski meta_started = False 1713be5bea1cSJakub Kicinski for _, attr in struct.member_list(): 1714be5bea1cSJakub Kicinski for type_filter in ['len', 'bit']: 1715be5bea1cSJakub Kicinski line = attr.presence_member(ri.ku_space, type_filter) 1716be5bea1cSJakub Kicinski if line: 1717be5bea1cSJakub Kicinski if not meta_started: 1718be5bea1cSJakub Kicinski ri.cw.block_start(line=f"struct") 1719be5bea1cSJakub Kicinski meta_started = True 1720be5bea1cSJakub Kicinski ri.cw.p(line) 1721be5bea1cSJakub Kicinski if meta_started: 1722be5bea1cSJakub Kicinski ri.cw.block_end(line='_present;') 1723be5bea1cSJakub Kicinski ri.cw.nl() 1724be5bea1cSJakub Kicinski 1725be5bea1cSJakub Kicinski for arg in struct.inherited: 1726be5bea1cSJakub Kicinski ri.cw.p(f"__u32 {arg};") 1727be5bea1cSJakub Kicinski 1728be5bea1cSJakub Kicinski for _, attr in struct.member_list(): 1729be5bea1cSJakub Kicinski attr.struct_member(ri) 1730be5bea1cSJakub Kicinski 1731be5bea1cSJakub Kicinski ri.cw.block_end(line=';') 1732be5bea1cSJakub Kicinski ri.cw.nl() 1733be5bea1cSJakub Kicinski 1734be5bea1cSJakub Kicinski 1735be5bea1cSJakub Kicinskidef print_type(ri, direction): 1736be5bea1cSJakub Kicinski _print_type(ri, direction, ri.struct[direction]) 1737be5bea1cSJakub Kicinski 1738be5bea1cSJakub Kicinski 1739be5bea1cSJakub Kicinskidef print_type_full(ri, struct): 1740be5bea1cSJakub Kicinski _print_type(ri, "", struct) 1741be5bea1cSJakub Kicinski 1742be5bea1cSJakub Kicinski 1743be5bea1cSJakub Kicinskidef print_type_helpers(ri, direction, deref=False): 1744be5bea1cSJakub Kicinski print_free_prototype(ri, direction) 17455d58f911SJakub Kicinski ri.cw.nl() 1746be5bea1cSJakub Kicinski 1747be5bea1cSJakub Kicinski if ri.ku_space == 'user' and direction == 'request': 1748be5bea1cSJakub Kicinski for _, attr in ri.struct[direction].member_list(): 1749be5bea1cSJakub Kicinski attr.setter(ri, ri.attr_set, direction, deref=deref) 1750be5bea1cSJakub Kicinski ri.cw.nl() 1751be5bea1cSJakub Kicinski 1752be5bea1cSJakub Kicinski 1753be5bea1cSJakub Kicinskidef print_req_type_helpers(ri): 17545d58f911SJakub Kicinski print_alloc_wrapper(ri, "request") 1755be5bea1cSJakub Kicinski print_type_helpers(ri, "request") 1756be5bea1cSJakub Kicinski 1757be5bea1cSJakub Kicinski 1758be5bea1cSJakub Kicinskidef print_rsp_type_helpers(ri): 1759be5bea1cSJakub Kicinski if 'reply' not in ri.op[ri.op_mode]: 1760be5bea1cSJakub Kicinski return 1761be5bea1cSJakub Kicinski print_type_helpers(ri, "reply") 1762be5bea1cSJakub Kicinski 1763be5bea1cSJakub Kicinski 1764be5bea1cSJakub Kicinskidef print_parse_prototype(ri, direction, terminate=True): 1765be5bea1cSJakub Kicinski suffix = "_rsp" if direction == "reply" else "_req" 1766be5bea1cSJakub Kicinski term = ';' if terminate else '' 1767be5bea1cSJakub Kicinski 1768be5bea1cSJakub Kicinski ri.cw.write_func_prot('void', f"{ri.op.render_name}{suffix}_parse", 1769be5bea1cSJakub Kicinski ['const struct nlattr **tb', 1770be5bea1cSJakub Kicinski f"struct {ri.op.render_name}{suffix} *req"], 1771be5bea1cSJakub Kicinski suffix=term) 1772be5bea1cSJakub Kicinski 1773be5bea1cSJakub Kicinski 1774be5bea1cSJakub Kicinskidef print_req_type(ri): 1775be5bea1cSJakub Kicinski print_type(ri, "request") 1776be5bea1cSJakub Kicinski 1777be5bea1cSJakub Kicinski 17785d58f911SJakub Kicinskidef print_req_free(ri): 17795d58f911SJakub Kicinski if 'request' not in ri.op[ri.op_mode]: 17805d58f911SJakub Kicinski return 17815d58f911SJakub Kicinski _free_type(ri, 'request', ri.struct['request']) 17825d58f911SJakub Kicinski 17835d58f911SJakub Kicinski 1784be5bea1cSJakub Kicinskidef print_rsp_type(ri): 1785be5bea1cSJakub Kicinski if (ri.op_mode == 'do' or ri.op_mode == 'dump') and 'reply' in ri.op[ri.op_mode]: 1786be5bea1cSJakub Kicinski direction = 'reply' 1787be5bea1cSJakub Kicinski elif ri.op_mode == 'event': 1788be5bea1cSJakub Kicinski direction = 'reply' 1789be5bea1cSJakub Kicinski else: 1790be5bea1cSJakub Kicinski return 1791be5bea1cSJakub Kicinski print_type(ri, direction) 1792be5bea1cSJakub Kicinski 1793be5bea1cSJakub Kicinski 1794be5bea1cSJakub Kicinskidef print_wrapped_type(ri): 1795be5bea1cSJakub Kicinski ri.cw.block_start(line=f"{type_name(ri, 'reply')}") 1796be5bea1cSJakub Kicinski if ri.op_mode == 'dump': 1797be5bea1cSJakub Kicinski ri.cw.p(f"{type_name(ri, 'reply')} *next;") 1798be5bea1cSJakub Kicinski elif ri.op_mode == 'notify' or ri.op_mode == 'event': 1799be5bea1cSJakub Kicinski ri.cw.p('__u16 family;') 1800be5bea1cSJakub Kicinski ri.cw.p('__u8 cmd;') 180159d814f0SJakub Kicinski ri.cw.p('struct ynl_ntf_base_type *next;') 1802be5bea1cSJakub Kicinski ri.cw.p(f"void (*free)({type_name(ri, 'reply')} *ntf);") 1803be5bea1cSJakub Kicinski ri.cw.p(f"{type_name(ri, 'reply', deref=True)} obj __attribute__ ((aligned (8)));") 1804be5bea1cSJakub Kicinski ri.cw.block_end(line=';') 1805be5bea1cSJakub Kicinski ri.cw.nl() 1806be5bea1cSJakub Kicinski print_free_prototype(ri, 'reply') 1807be5bea1cSJakub Kicinski ri.cw.nl() 1808be5bea1cSJakub Kicinski 1809be5bea1cSJakub Kicinski 1810be5bea1cSJakub Kicinskidef _free_type_members_iter(ri, struct): 1811be5bea1cSJakub Kicinski for _, attr in struct.member_list(): 1812be5bea1cSJakub Kicinski if attr.free_needs_iter(): 1813be5bea1cSJakub Kicinski ri.cw.p('unsigned int i;') 1814be5bea1cSJakub Kicinski ri.cw.nl() 1815be5bea1cSJakub Kicinski break 1816be5bea1cSJakub Kicinski 1817be5bea1cSJakub Kicinski 1818be5bea1cSJakub Kicinskidef _free_type_members(ri, var, struct, ref=''): 1819be5bea1cSJakub Kicinski for _, attr in struct.member_list(): 1820be5bea1cSJakub Kicinski attr.free(ri, var, ref) 1821be5bea1cSJakub Kicinski 1822be5bea1cSJakub Kicinski 1823be5bea1cSJakub Kicinskidef _free_type(ri, direction, struct): 1824be5bea1cSJakub Kicinski var = free_arg_name(direction) 1825be5bea1cSJakub Kicinski 1826be5bea1cSJakub Kicinski print_free_prototype(ri, direction, suffix='') 1827be5bea1cSJakub Kicinski ri.cw.block_start() 1828be5bea1cSJakub Kicinski _free_type_members_iter(ri, struct) 1829be5bea1cSJakub Kicinski _free_type_members(ri, var, struct) 1830be5bea1cSJakub Kicinski if direction: 1831be5bea1cSJakub Kicinski ri.cw.p(f'free({var});') 1832be5bea1cSJakub Kicinski ri.cw.block_end() 1833be5bea1cSJakub Kicinski ri.cw.nl() 1834be5bea1cSJakub Kicinski 1835be5bea1cSJakub Kicinski 1836be5bea1cSJakub Kicinskidef free_rsp_nested(ri, struct): 1837be5bea1cSJakub Kicinski _free_type(ri, "", struct) 1838be5bea1cSJakub Kicinski 1839be5bea1cSJakub Kicinski 1840be5bea1cSJakub Kicinskidef print_rsp_free(ri): 1841be5bea1cSJakub Kicinski if 'reply' not in ri.op[ri.op_mode]: 1842be5bea1cSJakub Kicinski return 1843be5bea1cSJakub Kicinski _free_type(ri, 'reply', ri.struct['reply']) 1844be5bea1cSJakub Kicinski 1845be5bea1cSJakub Kicinski 1846be5bea1cSJakub Kicinskidef print_dump_type_free(ri): 1847be5bea1cSJakub Kicinski sub_type = type_name(ri, 'reply') 1848be5bea1cSJakub Kicinski 1849be5bea1cSJakub Kicinski print_free_prototype(ri, 'reply', suffix='') 1850be5bea1cSJakub Kicinski ri.cw.block_start() 1851be5bea1cSJakub Kicinski ri.cw.p(f"{sub_type} *next = rsp;") 1852be5bea1cSJakub Kicinski ri.cw.nl() 1853dc0956c9SJakub Kicinski ri.cw.block_start(line='while ((void *)next != YNL_LIST_END)') 1854be5bea1cSJakub Kicinski _free_type_members_iter(ri, ri.struct['reply']) 1855be5bea1cSJakub Kicinski ri.cw.p('rsp = next;') 1856be5bea1cSJakub Kicinski ri.cw.p('next = rsp->next;') 1857be5bea1cSJakub Kicinski ri.cw.nl() 1858be5bea1cSJakub Kicinski 1859be5bea1cSJakub Kicinski _free_type_members(ri, 'rsp', ri.struct['reply'], ref='obj.') 1860be5bea1cSJakub Kicinski ri.cw.p(f'free(rsp);') 1861be5bea1cSJakub Kicinski ri.cw.block_end() 1862be5bea1cSJakub Kicinski ri.cw.block_end() 1863be5bea1cSJakub Kicinski ri.cw.nl() 1864be5bea1cSJakub Kicinski 1865be5bea1cSJakub Kicinski 1866be5bea1cSJakub Kicinskidef print_ntf_type_free(ri): 1867be5bea1cSJakub Kicinski print_free_prototype(ri, 'reply', suffix='') 1868be5bea1cSJakub Kicinski ri.cw.block_start() 1869be5bea1cSJakub Kicinski _free_type_members_iter(ri, ri.struct['reply']) 1870be5bea1cSJakub Kicinski _free_type_members(ri, 'rsp', ri.struct['reply'], ref='obj.') 1871be5bea1cSJakub Kicinski ri.cw.p(f'free(rsp);') 1872be5bea1cSJakub Kicinski ri.cw.block_end() 1873be5bea1cSJakub Kicinski ri.cw.nl() 1874be5bea1cSJakub Kicinski 1875be5bea1cSJakub Kicinski 1876be5bea1cSJakub Kicinskidef print_req_policy_fwd(cw, struct, ri=None, terminate=True): 1877fa8ba350SJiri Pirko if terminate and ri and policy_should_be_static(struct.family): 1878be5bea1cSJakub Kicinski return 1879be5bea1cSJakub Kicinski 1880be5bea1cSJakub Kicinski if terminate: 1881be5bea1cSJakub Kicinski prefix = 'extern ' 1882be5bea1cSJakub Kicinski else: 1883fa8ba350SJiri Pirko if ri and policy_should_be_static(struct.family): 1884be5bea1cSJakub Kicinski prefix = 'static ' 1885be5bea1cSJakub Kicinski else: 1886be5bea1cSJakub Kicinski prefix = '' 1887be5bea1cSJakub Kicinski 1888be5bea1cSJakub Kicinski suffix = ';' if terminate else ' = {' 1889be5bea1cSJakub Kicinski 1890be5bea1cSJakub Kicinski max_attr = struct.attr_max_val 1891be5bea1cSJakub Kicinski if ri: 1892be5bea1cSJakub Kicinski name = ri.op.render_name 1893be5bea1cSJakub Kicinski if ri.op.dual_policy: 1894be5bea1cSJakub Kicinski name += '_' + ri.op_mode 1895be5bea1cSJakub Kicinski else: 1896be5bea1cSJakub Kicinski name = struct.render_name 1897be5bea1cSJakub Kicinski cw.p(f"{prefix}const struct nla_policy {name}_nl_policy[{max_attr.enum_name} + 1]{suffix}") 1898be5bea1cSJakub Kicinski 1899be5bea1cSJakub Kicinski 1900be5bea1cSJakub Kicinskidef print_req_policy(cw, struct, ri=None): 1901be5bea1cSJakub Kicinski print_req_policy_fwd(cw, struct, ri=ri, terminate=False) 1902be5bea1cSJakub Kicinski for _, arg in struct.member_list(): 1903be5bea1cSJakub Kicinski arg.attr_policy(cw) 1904be5bea1cSJakub Kicinski cw.p("};") 1905cd3112ebSJakub Kicinski cw.nl() 1906be5bea1cSJakub Kicinski 1907be5bea1cSJakub Kicinski 1908be5bea1cSJakub Kicinskidef kernel_can_gen_family_struct(family): 1909be5bea1cSJakub Kicinski return family.proto == 'genetlink' 1910be5bea1cSJakub Kicinski 1911be5bea1cSJakub Kicinski 1912fa8ba350SJiri Pirkodef policy_should_be_static(family): 1913fa8ba350SJiri Pirko return family.kernel_policy == 'split' or kernel_can_gen_family_struct(family) 1914fa8ba350SJiri Pirko 1915fa8ba350SJiri Pirko 1916be5bea1cSJakub Kicinskidef print_kernel_op_table_fwd(family, cw, terminate): 1917be5bea1cSJakub Kicinski exported = not kernel_can_gen_family_struct(family) 1918be5bea1cSJakub Kicinski 1919be5bea1cSJakub Kicinski if not terminate or exported: 1920be5bea1cSJakub Kicinski cw.p(f"/* Ops table for {family.name} */") 1921be5bea1cSJakub Kicinski 1922be5bea1cSJakub Kicinski pol_to_struct = {'global': 'genl_small_ops', 1923be5bea1cSJakub Kicinski 'per-op': 'genl_ops', 1924be5bea1cSJakub Kicinski 'split': 'genl_split_ops'} 1925be5bea1cSJakub Kicinski struct_type = pol_to_struct[family.kernel_policy] 1926be5bea1cSJakub Kicinski 192756c874f7SJakub Kicinski if not exported: 192856c874f7SJakub Kicinski cnt = "" 192956c874f7SJakub Kicinski elif family.kernel_policy == 'split': 1930be5bea1cSJakub Kicinski cnt = 0 1931be5bea1cSJakub Kicinski for op in family.ops.values(): 1932be5bea1cSJakub Kicinski if 'do' in op: 1933be5bea1cSJakub Kicinski cnt += 1 1934be5bea1cSJakub Kicinski if 'dump' in op: 1935be5bea1cSJakub Kicinski cnt += 1 1936be5bea1cSJakub Kicinski else: 1937be5bea1cSJakub Kicinski cnt = len(family.ops) 1938be5bea1cSJakub Kicinski 1939be5bea1cSJakub Kicinski qual = 'static const' if not exported else 'const' 1940be5bea1cSJakub Kicinski line = f"{qual} struct {struct_type} {family.name}_nl_ops[{cnt}]" 1941be5bea1cSJakub Kicinski if terminate: 1942be5bea1cSJakub Kicinski cw.p(f"extern {line};") 1943be5bea1cSJakub Kicinski else: 1944be5bea1cSJakub Kicinski cw.block_start(line=line + ' =') 1945be5bea1cSJakub Kicinski 1946be5bea1cSJakub Kicinski if not terminate: 1947be5bea1cSJakub Kicinski return 1948be5bea1cSJakub Kicinski 1949be5bea1cSJakub Kicinski cw.nl() 1950be5bea1cSJakub Kicinski for name in family.hooks['pre']['do']['list']: 1951be5bea1cSJakub Kicinski cw.write_func_prot('int', c_lower(name), 1952be5bea1cSJakub Kicinski ['const struct genl_split_ops *ops', 1953be5bea1cSJakub Kicinski 'struct sk_buff *skb', 'struct genl_info *info'], suffix=';') 1954be5bea1cSJakub Kicinski for name in family.hooks['post']['do']['list']: 1955be5bea1cSJakub Kicinski cw.write_func_prot('void', c_lower(name), 1956be5bea1cSJakub Kicinski ['const struct genl_split_ops *ops', 1957be5bea1cSJakub Kicinski 'struct sk_buff *skb', 'struct genl_info *info'], suffix=';') 1958be5bea1cSJakub Kicinski for name in family.hooks['pre']['dump']['list']: 1959be5bea1cSJakub Kicinski cw.write_func_prot('int', c_lower(name), 1960be5bea1cSJakub Kicinski ['struct netlink_callback *cb'], suffix=';') 1961be5bea1cSJakub Kicinski for name in family.hooks['post']['dump']['list']: 1962be5bea1cSJakub Kicinski cw.write_func_prot('int', c_lower(name), 1963be5bea1cSJakub Kicinski ['struct netlink_callback *cb'], suffix=';') 1964be5bea1cSJakub Kicinski 1965be5bea1cSJakub Kicinski cw.nl() 1966be5bea1cSJakub Kicinski 1967be5bea1cSJakub Kicinski for op_name, op in family.ops.items(): 1968be5bea1cSJakub Kicinski if op.is_async: 1969be5bea1cSJakub Kicinski continue 1970be5bea1cSJakub Kicinski 1971be5bea1cSJakub Kicinski if 'do' in op: 1972be5bea1cSJakub Kicinski name = c_lower(f"{family.name}-nl-{op_name}-doit") 1973be5bea1cSJakub Kicinski cw.write_func_prot('int', name, 1974be5bea1cSJakub Kicinski ['struct sk_buff *skb', 'struct genl_info *info'], suffix=';') 1975be5bea1cSJakub Kicinski 1976be5bea1cSJakub Kicinski if 'dump' in op: 1977be5bea1cSJakub Kicinski name = c_lower(f"{family.name}-nl-{op_name}-dumpit") 1978be5bea1cSJakub Kicinski cw.write_func_prot('int', name, 1979be5bea1cSJakub Kicinski ['struct sk_buff *skb', 'struct netlink_callback *cb'], suffix=';') 1980be5bea1cSJakub Kicinski cw.nl() 1981be5bea1cSJakub Kicinski 1982be5bea1cSJakub Kicinski 1983be5bea1cSJakub Kicinskidef print_kernel_op_table_hdr(family, cw): 1984be5bea1cSJakub Kicinski print_kernel_op_table_fwd(family, cw, terminate=True) 1985be5bea1cSJakub Kicinski 1986be5bea1cSJakub Kicinski 1987be5bea1cSJakub Kicinskidef print_kernel_op_table(family, cw): 1988be5bea1cSJakub Kicinski print_kernel_op_table_fwd(family, cw, terminate=False) 1989be5bea1cSJakub Kicinski if family.kernel_policy == 'global' or family.kernel_policy == 'per-op': 1990be5bea1cSJakub Kicinski for op_name, op in family.ops.items(): 1991be5bea1cSJakub Kicinski if op.is_async: 1992be5bea1cSJakub Kicinski continue 1993be5bea1cSJakub Kicinski 1994be5bea1cSJakub Kicinski cw.block_start() 1995be5bea1cSJakub Kicinski members = [('cmd', op.enum_name)] 1996be5bea1cSJakub Kicinski if 'dont-validate' in op: 1997be5bea1cSJakub Kicinski members.append(('validate', 1998be5bea1cSJakub Kicinski ' | '.join([c_upper('genl-dont-validate-' + x) 1999be5bea1cSJakub Kicinski for x in op['dont-validate']])), ) 2000be5bea1cSJakub Kicinski for op_mode in ['do', 'dump']: 2001be5bea1cSJakub Kicinski if op_mode in op: 2002be5bea1cSJakub Kicinski name = c_lower(f"{family.name}-nl-{op_name}-{op_mode}it") 2003be5bea1cSJakub Kicinski members.append((op_mode + 'it', name)) 2004be5bea1cSJakub Kicinski if family.kernel_policy == 'per-op': 2005be5bea1cSJakub Kicinski struct = Struct(family, op['attribute-set'], 2006be5bea1cSJakub Kicinski type_list=op['do']['request']['attributes']) 2007be5bea1cSJakub Kicinski 2008be5bea1cSJakub Kicinski name = c_lower(f"{family.name}-{op_name}-nl-policy") 2009be5bea1cSJakub Kicinski members.append(('policy', name)) 2010be5bea1cSJakub Kicinski members.append(('maxattr', struct.attr_max_val.enum_name)) 2011be5bea1cSJakub Kicinski if 'flags' in op: 2012be5bea1cSJakub Kicinski members.append(('flags', ' | '.join([c_upper('genl-' + x) for x in op['flags']]))) 2013be5bea1cSJakub Kicinski cw.write_struct_init(members) 2014be5bea1cSJakub Kicinski cw.block_end(line=',') 2015be5bea1cSJakub Kicinski elif family.kernel_policy == 'split': 2016be5bea1cSJakub Kicinski cb_names = {'do': {'pre': 'pre_doit', 'post': 'post_doit'}, 2017be5bea1cSJakub Kicinski 'dump': {'pre': 'start', 'post': 'done'}} 2018be5bea1cSJakub Kicinski 2019be5bea1cSJakub Kicinski for op_name, op in family.ops.items(): 2020be5bea1cSJakub Kicinski for op_mode in ['do', 'dump']: 2021be5bea1cSJakub Kicinski if op.is_async or op_mode not in op: 2022be5bea1cSJakub Kicinski continue 2023be5bea1cSJakub Kicinski 2024be5bea1cSJakub Kicinski cw.block_start() 2025be5bea1cSJakub Kicinski members = [('cmd', op.enum_name)] 2026be5bea1cSJakub Kicinski if 'dont-validate' in op: 2027dc7b81a8SJiri Pirko dont_validate = [] 2028dc7b81a8SJiri Pirko for x in op['dont-validate']: 2029dc7b81a8SJiri Pirko if op_mode == 'do' and x in ['dump', 'dump-strict']: 2030dc7b81a8SJiri Pirko continue 2031dc7b81a8SJiri Pirko if op_mode == "dump" and x == 'strict': 2032dc7b81a8SJiri Pirko continue 2033dc7b81a8SJiri Pirko dont_validate.append(x) 2034dc7b81a8SJiri Pirko 20352c0e9f38SJiri Pirko if dont_validate: 2036be5bea1cSJakub Kicinski members.append(('validate', 2037be5bea1cSJakub Kicinski ' | '.join([c_upper('genl-dont-validate-' + x) 2038dc7b81a8SJiri Pirko for x in dont_validate])), ) 2039be5bea1cSJakub Kicinski name = c_lower(f"{family.name}-nl-{op_name}-{op_mode}it") 2040be5bea1cSJakub Kicinski if 'pre' in op[op_mode]: 2041be5bea1cSJakub Kicinski members.append((cb_names[op_mode]['pre'], c_lower(op[op_mode]['pre']))) 2042be5bea1cSJakub Kicinski members.append((op_mode + 'it', name)) 2043be5bea1cSJakub Kicinski if 'post' in op[op_mode]: 2044be5bea1cSJakub Kicinski members.append((cb_names[op_mode]['post'], c_lower(op[op_mode]['post']))) 2045be5bea1cSJakub Kicinski if 'request' in op[op_mode]: 2046be5bea1cSJakub Kicinski struct = Struct(family, op['attribute-set'], 2047be5bea1cSJakub Kicinski type_list=op[op_mode]['request']['attributes']) 2048be5bea1cSJakub Kicinski 2049be5bea1cSJakub Kicinski if op.dual_policy: 2050be5bea1cSJakub Kicinski name = c_lower(f"{family.name}-{op_name}-{op_mode}-nl-policy") 2051be5bea1cSJakub Kicinski else: 2052be5bea1cSJakub Kicinski name = c_lower(f"{family.name}-{op_name}-nl-policy") 2053be5bea1cSJakub Kicinski members.append(('policy', name)) 2054be5bea1cSJakub Kicinski members.append(('maxattr', struct.attr_max_val.enum_name)) 2055be5bea1cSJakub Kicinski flags = (op['flags'] if 'flags' in op else []) + ['cmd-cap-' + op_mode] 2056be5bea1cSJakub Kicinski members.append(('flags', ' | '.join([c_upper('genl-' + x) for x in flags]))) 2057be5bea1cSJakub Kicinski cw.write_struct_init(members) 2058be5bea1cSJakub Kicinski cw.block_end(line=',') 2059be5bea1cSJakub Kicinski 2060be5bea1cSJakub Kicinski cw.block_end(line=';') 2061be5bea1cSJakub Kicinski cw.nl() 2062be5bea1cSJakub Kicinski 2063be5bea1cSJakub Kicinski 2064be5bea1cSJakub Kicinskidef print_kernel_mcgrp_hdr(family, cw): 2065be5bea1cSJakub Kicinski if not family.mcgrps['list']: 2066be5bea1cSJakub Kicinski return 2067be5bea1cSJakub Kicinski 2068be5bea1cSJakub Kicinski cw.block_start('enum') 2069be5bea1cSJakub Kicinski for grp in family.mcgrps['list']: 2070be5bea1cSJakub Kicinski grp_id = c_upper(f"{family.name}-nlgrp-{grp['name']},") 2071be5bea1cSJakub Kicinski cw.p(grp_id) 2072be5bea1cSJakub Kicinski cw.block_end(';') 2073be5bea1cSJakub Kicinski cw.nl() 2074be5bea1cSJakub Kicinski 2075be5bea1cSJakub Kicinski 2076be5bea1cSJakub Kicinskidef print_kernel_mcgrp_src(family, cw): 2077be5bea1cSJakub Kicinski if not family.mcgrps['list']: 2078be5bea1cSJakub Kicinski return 2079be5bea1cSJakub Kicinski 2080be5bea1cSJakub Kicinski cw.block_start('static const struct genl_multicast_group ' + family.name + '_nl_mcgrps[] =') 2081be5bea1cSJakub Kicinski for grp in family.mcgrps['list']: 2082be5bea1cSJakub Kicinski name = grp['name'] 2083be5bea1cSJakub Kicinski grp_id = c_upper(f"{family.name}-nlgrp-{name}") 2084be5bea1cSJakub Kicinski cw.p('[' + grp_id + '] = { "' + name + '", },') 2085be5bea1cSJakub Kicinski cw.block_end(';') 2086be5bea1cSJakub Kicinski cw.nl() 2087be5bea1cSJakub Kicinski 2088be5bea1cSJakub Kicinski 2089be5bea1cSJakub Kicinskidef print_kernel_family_struct_hdr(family, cw): 2090be5bea1cSJakub Kicinski if not kernel_can_gen_family_struct(family): 2091be5bea1cSJakub Kicinski return 2092be5bea1cSJakub Kicinski 2093be5bea1cSJakub Kicinski cw.p(f"extern struct genl_family {family.name}_nl_family;") 2094be5bea1cSJakub Kicinski cw.nl() 2095be5bea1cSJakub Kicinski 2096be5bea1cSJakub Kicinski 2097be5bea1cSJakub Kicinskidef print_kernel_family_struct_src(family, cw): 2098be5bea1cSJakub Kicinski if not kernel_can_gen_family_struct(family): 2099be5bea1cSJakub Kicinski return 2100be5bea1cSJakub Kicinski 2101be5bea1cSJakub Kicinski cw.block_start(f"struct genl_family {family.name}_nl_family __ro_after_init =") 2102be5bea1cSJakub Kicinski cw.p('.name\t\t= ' + family.fam_key + ',') 2103be5bea1cSJakub Kicinski cw.p('.version\t= ' + family.ver_key + ',') 2104be5bea1cSJakub Kicinski cw.p('.netnsok\t= true,') 2105be5bea1cSJakub Kicinski cw.p('.parallel_ops\t= true,') 2106be5bea1cSJakub Kicinski cw.p('.module\t\t= THIS_MODULE,') 2107be5bea1cSJakub Kicinski if family.kernel_policy == 'per-op': 2108be5bea1cSJakub Kicinski cw.p(f'.ops\t\t= {family.name}_nl_ops,') 2109be5bea1cSJakub Kicinski cw.p(f'.n_ops\t\t= ARRAY_SIZE({family.name}_nl_ops),') 2110be5bea1cSJakub Kicinski elif family.kernel_policy == 'split': 2111be5bea1cSJakub Kicinski cw.p(f'.split_ops\t= {family.name}_nl_ops,') 2112be5bea1cSJakub Kicinski cw.p(f'.n_split_ops\t= ARRAY_SIZE({family.name}_nl_ops),') 2113be5bea1cSJakub Kicinski if family.mcgrps['list']: 2114be5bea1cSJakub Kicinski cw.p(f'.mcgrps\t\t= {family.name}_nl_mcgrps,') 2115be5bea1cSJakub Kicinski cw.p(f'.n_mcgrps\t= ARRAY_SIZE({family.name}_nl_mcgrps),') 2116be5bea1cSJakub Kicinski cw.block_end(';') 2117be5bea1cSJakub Kicinski 2118be5bea1cSJakub Kicinski 2119be5bea1cSJakub Kicinskidef uapi_enum_start(family, cw, obj, ckey='', enum_name='enum-name'): 2120be5bea1cSJakub Kicinski start_line = 'enum' 2121be5bea1cSJakub Kicinski if enum_name in obj: 2122be5bea1cSJakub Kicinski if obj[enum_name]: 2123be5bea1cSJakub Kicinski start_line = 'enum ' + c_lower(obj[enum_name]) 2124be5bea1cSJakub Kicinski elif ckey and ckey in obj: 2125be5bea1cSJakub Kicinski start_line = 'enum ' + family.name + '_' + c_lower(obj[ckey]) 2126be5bea1cSJakub Kicinski cw.block_start(line=start_line) 2127be5bea1cSJakub Kicinski 2128be5bea1cSJakub Kicinski 2129be5bea1cSJakub Kicinskidef render_uapi(family, cw): 2130be5bea1cSJakub Kicinski hdr_prot = f"_UAPI_LINUX_{family.name.upper()}_H" 2131be5bea1cSJakub Kicinski cw.p('#ifndef ' + hdr_prot) 2132be5bea1cSJakub Kicinski cw.p('#define ' + hdr_prot) 2133be5bea1cSJakub Kicinski cw.nl() 2134be5bea1cSJakub Kicinski 2135be5bea1cSJakub Kicinski defines = [(family.fam_key, family["name"]), 2136be5bea1cSJakub Kicinski (family.ver_key, family.get('version', 1))] 2137be5bea1cSJakub Kicinski cw.writes_defines(defines) 2138be5bea1cSJakub Kicinski cw.nl() 2139be5bea1cSJakub Kicinski 2140be5bea1cSJakub Kicinski defines = [] 2141be5bea1cSJakub Kicinski for const in family['definitions']: 2142be5bea1cSJakub Kicinski if const['type'] != 'const': 2143be5bea1cSJakub Kicinski cw.writes_defines(defines) 2144be5bea1cSJakub Kicinski defines = [] 2145be5bea1cSJakub Kicinski cw.nl() 2146be5bea1cSJakub Kicinski 214766fa34b9SJakub Kicinski # Write kdoc for enum and flags (one day maybe also structs) 214866fa34b9SJakub Kicinski if const['type'] == 'enum' or const['type'] == 'flags': 2149be5bea1cSJakub Kicinski enum = family.consts[const['name']] 2150be5bea1cSJakub Kicinski 2151be5bea1cSJakub Kicinski if enum.has_doc(): 2152be5bea1cSJakub Kicinski cw.p('/**') 2153be5bea1cSJakub Kicinski doc = '' 2154be5bea1cSJakub Kicinski if 'doc' in enum: 2155be5bea1cSJakub Kicinski doc = ' - ' + enum['doc'] 2156be5bea1cSJakub Kicinski cw.write_doc_line(enum.enum_name + doc) 21576517a60bSJakub Kicinski for entry in enum.entries.values(): 2158be5bea1cSJakub Kicinski if entry.has_doc(): 2159be5bea1cSJakub Kicinski doc = '@' + entry.c_name + ': ' + entry['doc'] 2160be5bea1cSJakub Kicinski cw.write_doc_line(doc) 2161be5bea1cSJakub Kicinski cw.p(' */') 2162be5bea1cSJakub Kicinski 2163be5bea1cSJakub Kicinski uapi_enum_start(family, cw, const, 'name') 2164be5bea1cSJakub Kicinski name_pfx = const.get('name-prefix', f"{family.name}-{const['name']}-") 21656517a60bSJakub Kicinski for entry in enum.entries.values(): 2166be5bea1cSJakub Kicinski suffix = ',' 216766fa34b9SJakub Kicinski if entry.value_change: 216866fa34b9SJakub Kicinski suffix = f" = {entry.user_value()}" + suffix 2169be5bea1cSJakub Kicinski cw.p(entry.c_name + suffix) 2170be5bea1cSJakub Kicinski 2171be5bea1cSJakub Kicinski if const.get('render-max', False): 2172be5bea1cSJakub Kicinski cw.nl() 217337844828SStanislav Fomichev cw.p('/* private: */') 21748f76a4f8SLorenzo Bianconi if const['type'] == 'flags': 21758f76a4f8SLorenzo Bianconi max_name = c_upper(name_pfx + 'mask') 21768f76a4f8SLorenzo Bianconi max_val = f' = {enum.get_mask()},' 21778f76a4f8SLorenzo Bianconi cw.p(max_name + max_val) 21788f76a4f8SLorenzo Bianconi else: 2179be5bea1cSJakub Kicinski max_name = c_upper(name_pfx + 'max') 2180be5bea1cSJakub Kicinski cw.p('__' + max_name + ',') 2181be5bea1cSJakub Kicinski cw.p(max_name + ' = (__' + max_name + ' - 1)') 2182be5bea1cSJakub Kicinski cw.block_end(line=';') 2183be5bea1cSJakub Kicinski cw.nl() 2184be5bea1cSJakub Kicinski elif const['type'] == 'const': 2185be5bea1cSJakub Kicinski defines.append([c_upper(family.get('c-define-name', 2186be5bea1cSJakub Kicinski f"{family.name}-{const['name']}")), 2187be5bea1cSJakub Kicinski const['value']]) 2188be5bea1cSJakub Kicinski 2189be5bea1cSJakub Kicinski if defines: 2190be5bea1cSJakub Kicinski cw.writes_defines(defines) 2191be5bea1cSJakub Kicinski cw.nl() 2192be5bea1cSJakub Kicinski 2193be5bea1cSJakub Kicinski max_by_define = family.get('max-by-define', False) 2194be5bea1cSJakub Kicinski 219530a5c6c8SJakub Kicinski for _, attr_set in family.attr_sets.items(): 2196be5bea1cSJakub Kicinski if attr_set.subset_of: 2197be5bea1cSJakub Kicinski continue 2198be5bea1cSJakub Kicinski 2199be5bea1cSJakub Kicinski cnt_name = c_upper(family.get('attr-cnt-name', f"__{attr_set.name_prefix}MAX")) 2200be5bea1cSJakub Kicinski max_value = f"({cnt_name} - 1)" 2201be5bea1cSJakub Kicinski 2202be5bea1cSJakub Kicinski val = 0 2203be5bea1cSJakub Kicinski uapi_enum_start(family, cw, attr_set.yaml, 'enum-name') 2204be5bea1cSJakub Kicinski for _, attr in attr_set.items(): 2205be5bea1cSJakub Kicinski suffix = ',' 220630a5c6c8SJakub Kicinski if attr.value != val: 220730a5c6c8SJakub Kicinski suffix = f" = {attr.value}," 220830a5c6c8SJakub Kicinski val = attr.value 2209be5bea1cSJakub Kicinski val += 1 2210be5bea1cSJakub Kicinski cw.p(attr.enum_name + suffix) 2211be5bea1cSJakub Kicinski cw.nl() 2212be5bea1cSJakub Kicinski cw.p(cnt_name + ('' if max_by_define else ',')) 2213be5bea1cSJakub Kicinski if not max_by_define: 2214be5bea1cSJakub Kicinski cw.p(f"{attr_set.max_name} = {max_value}") 2215be5bea1cSJakub Kicinski cw.block_end(line=';') 2216be5bea1cSJakub Kicinski if max_by_define: 2217be5bea1cSJakub Kicinski cw.p(f"#define {attr_set.max_name} {max_value}") 2218be5bea1cSJakub Kicinski cw.nl() 2219be5bea1cSJakub Kicinski 2220be5bea1cSJakub Kicinski # Commands 2221be5bea1cSJakub Kicinski separate_ntf = 'async-prefix' in family['operations'] 2222be5bea1cSJakub Kicinski 2223be5bea1cSJakub Kicinski max_name = c_upper(family.get('cmd-max-name', f"{family.op_prefix}MAX")) 2224be5bea1cSJakub Kicinski cnt_name = c_upper(family.get('cmd-cnt-name', f"__{family.op_prefix}MAX")) 2225be5bea1cSJakub Kicinski max_value = f"({cnt_name} - 1)" 2226be5bea1cSJakub Kicinski 2227be5bea1cSJakub Kicinski uapi_enum_start(family, cw, family['operations'], 'enum-name') 2228ad4fafcdSJakub Kicinski val = 0 222930a5c6c8SJakub Kicinski for op in family.msgs.values(): 2230be5bea1cSJakub Kicinski if separate_ntf and ('notify' in op or 'event' in op): 2231be5bea1cSJakub Kicinski continue 2232be5bea1cSJakub Kicinski 2233be5bea1cSJakub Kicinski suffix = ',' 2234ad4fafcdSJakub Kicinski if op.value != val: 2235ad4fafcdSJakub Kicinski suffix = f" = {op.value}," 2236ad4fafcdSJakub Kicinski val = op.value 2237be5bea1cSJakub Kicinski cw.p(op.enum_name + suffix) 2238ad4fafcdSJakub Kicinski val += 1 2239be5bea1cSJakub Kicinski cw.nl() 2240be5bea1cSJakub Kicinski cw.p(cnt_name + ('' if max_by_define else ',')) 2241be5bea1cSJakub Kicinski if not max_by_define: 2242be5bea1cSJakub Kicinski cw.p(f"{max_name} = {max_value}") 2243be5bea1cSJakub Kicinski cw.block_end(line=';') 2244be5bea1cSJakub Kicinski if max_by_define: 2245be5bea1cSJakub Kicinski cw.p(f"#define {max_name} {max_value}") 2246be5bea1cSJakub Kicinski cw.nl() 2247be5bea1cSJakub Kicinski 2248be5bea1cSJakub Kicinski if separate_ntf: 2249be5bea1cSJakub Kicinski uapi_enum_start(family, cw, family['operations'], enum_name='async-enum') 225030a5c6c8SJakub Kicinski for op in family.msgs.values(): 2251be5bea1cSJakub Kicinski if separate_ntf and not ('notify' in op or 'event' in op): 2252be5bea1cSJakub Kicinski continue 2253be5bea1cSJakub Kicinski 2254be5bea1cSJakub Kicinski suffix = ',' 2255be5bea1cSJakub Kicinski if 'value' in op: 2256be5bea1cSJakub Kicinski suffix = f" = {op['value']}," 2257be5bea1cSJakub Kicinski cw.p(op.enum_name + suffix) 2258be5bea1cSJakub Kicinski cw.block_end(line=';') 2259be5bea1cSJakub Kicinski cw.nl() 2260be5bea1cSJakub Kicinski 2261be5bea1cSJakub Kicinski # Multicast 2262be5bea1cSJakub Kicinski defines = [] 2263be5bea1cSJakub Kicinski for grp in family.mcgrps['list']: 2264be5bea1cSJakub Kicinski name = grp['name'] 2265be5bea1cSJakub Kicinski defines.append([c_upper(grp.get('c-define-name', f"{family.name}-mcgrp-{name}")), 2266be5bea1cSJakub Kicinski f'{name}']) 2267be5bea1cSJakub Kicinski cw.nl() 2268be5bea1cSJakub Kicinski if defines: 2269be5bea1cSJakub Kicinski cw.writes_defines(defines) 2270be5bea1cSJakub Kicinski cw.nl() 2271be5bea1cSJakub Kicinski 2272be5bea1cSJakub Kicinski cw.p(f'#endif /* {hdr_prot} */') 2273be5bea1cSJakub Kicinski 2274be5bea1cSJakub Kicinski 227559d814f0SJakub Kicinskidef _render_user_ntf_entry(ri, op): 227659d814f0SJakub Kicinski ri.cw.block_start(line=f"[{op.enum_name}] = ") 227759d814f0SJakub Kicinski ri.cw.p(f".alloc_sz\t= sizeof({type_name(ri, 'event')}),") 227859d814f0SJakub Kicinski ri.cw.p(f".cb\t\t= {op_prefix(ri, 'reply', deref=True)}_parse,") 227959d814f0SJakub Kicinski ri.cw.p(f".policy\t\t= &{ri.struct['reply'].render_name}_nest,") 228059d814f0SJakub Kicinski ri.cw.p(f".free\t\t= (void *){op_prefix(ri, 'notify')}_free,") 228159d814f0SJakub Kicinski ri.cw.block_end(line=',') 228259d814f0SJakub Kicinski 228359d814f0SJakub Kicinski 22848cb6afb3SJakub Kicinskidef render_user_family(family, cw, prototype): 22858cb6afb3SJakub Kicinski symbol = f'const struct ynl_family ynl_{family.c_name}_family' 22868cb6afb3SJakub Kicinski if prototype: 22878cb6afb3SJakub Kicinski cw.p(f'extern {symbol};') 228859d814f0SJakub Kicinski return 228959d814f0SJakub Kicinski 2290ced15688SJakub Kicinski if family.ntfs: 229159d814f0SJakub Kicinski cw.block_start(line=f"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ") 2292ced15688SJakub Kicinski for ntf_op_name, ntf_op in family.ntfs.items(): 22936da3424fSJakub Kicinski if 'notify' in ntf_op: 2294ced15688SJakub Kicinski op = family.ops[ntf_op['notify']] 22956f96ec73SJakub Kicinski ri = RenderInfo(cw, family, "user", op, "notify") 22966da3424fSJakub Kicinski elif 'event' in ntf_op: 22976f96ec73SJakub Kicinski ri = RenderInfo(cw, family, "user", ntf_op, "event") 22986da3424fSJakub Kicinski else: 22996da3424fSJakub Kicinski raise Exception('Invalid notification ' + ntf_op_name) 2300ced15688SJakub Kicinski _render_user_ntf_entry(ri, ntf_op) 230159d814f0SJakub Kicinski for op_name, op in family.ops.items(): 230259d814f0SJakub Kicinski if 'event' not in op: 230359d814f0SJakub Kicinski continue 23046f96ec73SJakub Kicinski ri = RenderInfo(cw, family, "user", op, "event") 230559d814f0SJakub Kicinski _render_user_ntf_entry(ri, op) 230659d814f0SJakub Kicinski cw.block_end(line=";") 230759d814f0SJakub Kicinski cw.nl() 230859d814f0SJakub Kicinski 23098cb6afb3SJakub Kicinski cw.block_start(f'{symbol} = ') 231059d814f0SJakub Kicinski cw.p(f'.name\t\t= "{family.name}",') 2311ced15688SJakub Kicinski if family.ntfs: 231259d814f0SJakub Kicinski cw.p(f".ntf_info\t= {family['name']}_ntf_info,") 231359d814f0SJakub Kicinski cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),") 23148cb6afb3SJakub Kicinski cw.block_end(line=';') 23158cb6afb3SJakub Kicinski 23168cb6afb3SJakub Kicinski 2317be5bea1cSJakub Kicinskidef find_kernel_root(full_path): 2318be5bea1cSJakub Kicinski sub_path = '' 2319be5bea1cSJakub Kicinski while True: 2320be5bea1cSJakub Kicinski sub_path = os.path.join(os.path.basename(full_path), sub_path) 2321be5bea1cSJakub Kicinski full_path = os.path.dirname(full_path) 2322be5bea1cSJakub Kicinski maintainers = os.path.join(full_path, "MAINTAINERS") 2323be5bea1cSJakub Kicinski if os.path.exists(maintainers): 2324be5bea1cSJakub Kicinski return full_path, sub_path[:-1] 2325be5bea1cSJakub Kicinski 2326be5bea1cSJakub Kicinski 2327be5bea1cSJakub Kicinskidef main(): 2328be5bea1cSJakub Kicinski parser = argparse.ArgumentParser(description='Netlink simple parsing generator') 2329be5bea1cSJakub Kicinski parser.add_argument('--mode', dest='mode', type=str, required=True) 2330be5bea1cSJakub Kicinski parser.add_argument('--spec', dest='spec', type=str, required=True) 2331be5bea1cSJakub Kicinski parser.add_argument('--header', dest='header', action='store_true', default=None) 2332be5bea1cSJakub Kicinski parser.add_argument('--source', dest='header', action='store_false') 2333be5bea1cSJakub Kicinski parser.add_argument('--user-header', nargs='+', default=[]) 2334008bcd68SJakub Kicinski parser.add_argument('--exclude-op', action='append', default=[]) 2335a02430c0SJakub Kicinski parser.add_argument('-o', dest='out_file', type=str, default=None) 2336be5bea1cSJakub Kicinski args = parser.parse_args() 2337be5bea1cSJakub Kicinski 2338be5bea1cSJakub Kicinski if args.header is None: 2339be5bea1cSJakub Kicinski parser.error("--header or --source is required") 2340be5bea1cSJakub Kicinski 2341008bcd68SJakub Kicinski exclude_ops = [re.compile(expr) for expr in args.exclude_op] 2342008bcd68SJakub Kicinski 2343be5bea1cSJakub Kicinski try: 2344008bcd68SJakub Kicinski parsed = Family(args.spec, exclude_ops) 2345cfab77c0SJakub Kicinski if parsed.license != '((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)': 2346cfab77c0SJakub Kicinski print('Spec license:', parsed.license) 2347cfab77c0SJakub Kicinski print('License must be: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)') 2348cfab77c0SJakub Kicinski os.sys.exit(1) 2349be5bea1cSJakub Kicinski except yaml.YAMLError as exc: 2350be5bea1cSJakub Kicinski print(exc) 2351be5bea1cSJakub Kicinski os.sys.exit(1) 2352be5bea1cSJakub Kicinski return 2353be5bea1cSJakub Kicinski 2354ff6db4b5SJakub Kicinski supported_models = ['unified'] 2355eab7be68SJiri Pirko if args.mode in ['user', 'kernel']: 2356ff6db4b5SJakub Kicinski supported_models += ['directional'] 2357ff6db4b5SJakub Kicinski if parsed.msg_id_model not in supported_models: 2358ff6db4b5SJakub Kicinski print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation') 2359ff6db4b5SJakub Kicinski os.sys.exit(1) 2360ff6db4b5SJakub Kicinski 2361a02430c0SJakub Kicinski cw = CodeWriter(BaseNlLib(), args.out_file) 2362be5bea1cSJakub Kicinski 2363be5bea1cSJakub Kicinski _, spec_kernel = find_kernel_root(args.spec) 2364cfab77c0SJakub Kicinski if args.mode == 'uapi' or args.header: 2365cfab77c0SJakub Kicinski cw.p(f'/* SPDX-License-Identifier: {parsed.license} */') 2366be5bea1cSJakub Kicinski else: 2367cfab77c0SJakub Kicinski cw.p(f'// SPDX-License-Identifier: {parsed.license}') 2368be5bea1cSJakub Kicinski cw.p("/* Do not edit directly, auto-generated from: */") 2369be5bea1cSJakub Kicinski cw.p(f"/*\t{spec_kernel} */") 2370be5bea1cSJakub Kicinski cw.p(f"/* YNL-GEN {args.mode} {'header' if args.header else 'source'} */") 237133eedb00SJakub Kicinski if args.exclude_op or args.user_header: 237233eedb00SJakub Kicinski line = '' 237333eedb00SJakub Kicinski line += ' --user-header '.join([''] + args.user_header) 237433eedb00SJakub Kicinski line += ' --exclude-op '.join([''] + args.exclude_op) 237533eedb00SJakub Kicinski cw.p(f'/* YNL-ARG{line} */') 2376be5bea1cSJakub Kicinski cw.nl() 2377be5bea1cSJakub Kicinski 2378be5bea1cSJakub Kicinski if args.mode == 'uapi': 2379be5bea1cSJakub Kicinski render_uapi(parsed, cw) 2380be5bea1cSJakub Kicinski return 2381be5bea1cSJakub Kicinski 2382be5bea1cSJakub Kicinski hdr_prot = f"_LINUX_{parsed.name.upper()}_GEN_H" 2383be5bea1cSJakub Kicinski if args.header: 2384be5bea1cSJakub Kicinski cw.p('#ifndef ' + hdr_prot) 2385be5bea1cSJakub Kicinski cw.p('#define ' + hdr_prot) 2386be5bea1cSJakub Kicinski cw.nl() 2387be5bea1cSJakub Kicinski 2388be5bea1cSJakub Kicinski if args.mode == 'kernel': 2389be5bea1cSJakub Kicinski cw.p('#include <net/netlink.h>') 2390be5bea1cSJakub Kicinski cw.p('#include <net/genetlink.h>') 2391be5bea1cSJakub Kicinski cw.nl() 2392be5bea1cSJakub Kicinski if not args.header: 2393be5bea1cSJakub Kicinski if args.out_file: 2394be5bea1cSJakub Kicinski cw.p(f'#include "{os.path.basename(args.out_file[:-2])}.h"') 2395be5bea1cSJakub Kicinski cw.nl() 23969b66ee06SJakub Kicinski headers = ['uapi/' + parsed.uapi_header] 23979b66ee06SJakub Kicinski else: 239891dfaef2SJakub Kicinski cw.p('#include <stdlib.h>') 239991dfaef2SJakub Kicinski cw.p('#include <string.h>') 240030b5c720SJakub Kicinski if args.header: 240191dfaef2SJakub Kicinski cw.p('#include <linux/types.h>') 240291dfaef2SJakub Kicinski else: 240391dfaef2SJakub Kicinski cw.p(f'#include "{parsed.name}-user.h"') 240491dfaef2SJakub Kicinski cw.p('#include "ynl.h"') 2405be5bea1cSJakub Kicinski headers = [parsed.uapi_header] 2406be5bea1cSJakub Kicinski for definition in parsed['definitions']: 2407be5bea1cSJakub Kicinski if 'header' in definition: 2408be5bea1cSJakub Kicinski headers.append(definition['header']) 2409be5bea1cSJakub Kicinski for one in headers: 2410be5bea1cSJakub Kicinski cw.p(f"#include <{one}>") 2411be5bea1cSJakub Kicinski cw.nl() 2412be5bea1cSJakub Kicinski 2413be5bea1cSJakub Kicinski if args.mode == "user": 2414be5bea1cSJakub Kicinski if not args.header: 2415be5bea1cSJakub Kicinski cw.p("#include <libmnl/libmnl.h>") 2416be5bea1cSJakub Kicinski cw.p("#include <linux/genetlink.h>") 2417be5bea1cSJakub Kicinski cw.nl() 2418be5bea1cSJakub Kicinski for one in args.user_header: 2419be5bea1cSJakub Kicinski cw.p(f'#include "{one}"') 2420be5bea1cSJakub Kicinski else: 2421be5bea1cSJakub Kicinski cw.p('struct ynl_sock;') 2422be5bea1cSJakub Kicinski cw.nl() 24238cb6afb3SJakub Kicinski render_user_family(parsed, cw, True) 24248cb6afb3SJakub Kicinski cw.nl() 2425be5bea1cSJakub Kicinski 2426be5bea1cSJakub Kicinski if args.mode == "kernel": 2427be5bea1cSJakub Kicinski if args.header: 2428be5bea1cSJakub Kicinski for _, struct in sorted(parsed.pure_nested_structs.items()): 2429be5bea1cSJakub Kicinski if struct.request: 2430be5bea1cSJakub Kicinski cw.p('/* Common nested types */') 2431be5bea1cSJakub Kicinski break 2432be5bea1cSJakub Kicinski for attr_set, struct in sorted(parsed.pure_nested_structs.items()): 2433be5bea1cSJakub Kicinski if struct.request: 2434be5bea1cSJakub Kicinski print_req_policy_fwd(cw, struct) 2435be5bea1cSJakub Kicinski cw.nl() 2436be5bea1cSJakub Kicinski 2437be5bea1cSJakub Kicinski if parsed.kernel_policy == 'global': 2438be5bea1cSJakub Kicinski cw.p(f"/* Global operation policy for {parsed.name} */") 2439be5bea1cSJakub Kicinski 2440be5bea1cSJakub Kicinski struct = Struct(parsed, parsed.global_policy_set, type_list=parsed.global_policy) 2441be5bea1cSJakub Kicinski print_req_policy_fwd(cw, struct) 2442be5bea1cSJakub Kicinski cw.nl() 2443be5bea1cSJakub Kicinski 2444be5bea1cSJakub Kicinski if parsed.kernel_policy in {'per-op', 'split'}: 2445be5bea1cSJakub Kicinski for op_name, op in parsed.ops.items(): 2446be5bea1cSJakub Kicinski if 'do' in op and 'event' not in op: 24476f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, op, "do") 2448be5bea1cSJakub Kicinski print_req_policy_fwd(cw, ri.struct['request'], ri=ri) 2449be5bea1cSJakub Kicinski cw.nl() 2450be5bea1cSJakub Kicinski 2451be5bea1cSJakub Kicinski print_kernel_op_table_hdr(parsed, cw) 2452be5bea1cSJakub Kicinski print_kernel_mcgrp_hdr(parsed, cw) 2453be5bea1cSJakub Kicinski print_kernel_family_struct_hdr(parsed, cw) 2454be5bea1cSJakub Kicinski else: 2455be5bea1cSJakub Kicinski for _, struct in sorted(parsed.pure_nested_structs.items()): 2456be5bea1cSJakub Kicinski if struct.request: 2457be5bea1cSJakub Kicinski cw.p('/* Common nested types */') 2458be5bea1cSJakub Kicinski break 2459be5bea1cSJakub Kicinski for attr_set, struct in sorted(parsed.pure_nested_structs.items()): 2460be5bea1cSJakub Kicinski if struct.request: 2461be5bea1cSJakub Kicinski print_req_policy(cw, struct) 2462be5bea1cSJakub Kicinski cw.nl() 2463be5bea1cSJakub Kicinski 2464be5bea1cSJakub Kicinski if parsed.kernel_policy == 'global': 2465be5bea1cSJakub Kicinski cw.p(f"/* Global operation policy for {parsed.name} */") 2466be5bea1cSJakub Kicinski 2467be5bea1cSJakub Kicinski struct = Struct(parsed, parsed.global_policy_set, type_list=parsed.global_policy) 2468be5bea1cSJakub Kicinski print_req_policy(cw, struct) 2469be5bea1cSJakub Kicinski cw.nl() 2470be5bea1cSJakub Kicinski 2471be5bea1cSJakub Kicinski for op_name, op in parsed.ops.items(): 2472be5bea1cSJakub Kicinski if parsed.kernel_policy in {'per-op', 'split'}: 2473eaf317e7SJakub Kicinski for op_mode in ['do', 'dump']: 2474be5bea1cSJakub Kicinski if op_mode in op and 'request' in op[op_mode]: 2475be5bea1cSJakub Kicinski cw.p(f"/* {op.enum_name} - {op_mode} */") 24766f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, op, op_mode) 2477be5bea1cSJakub Kicinski print_req_policy(cw, ri.struct['request'], ri=ri) 2478be5bea1cSJakub Kicinski cw.nl() 2479be5bea1cSJakub Kicinski 2480be5bea1cSJakub Kicinski print_kernel_op_table(parsed, cw) 2481be5bea1cSJakub Kicinski print_kernel_mcgrp_src(parsed, cw) 2482be5bea1cSJakub Kicinski print_kernel_family_struct_src(parsed, cw) 2483be5bea1cSJakub Kicinski 2484be5bea1cSJakub Kicinski if args.mode == "user": 2485be5bea1cSJakub Kicinski if args.header: 248621b6e302SJakub Kicinski cw.p('/* Enums */') 248721b6e302SJakub Kicinski put_op_name_fwd(parsed, cw) 248821b6e302SJakub Kicinski 248921b6e302SJakub Kicinski for name, const in parsed.consts.items(): 249021b6e302SJakub Kicinski if isinstance(const, EnumSet): 249121b6e302SJakub Kicinski put_enum_to_str_fwd(parsed, cw, const) 249221b6e302SJakub Kicinski cw.nl() 249321b6e302SJakub Kicinski 2494be5bea1cSJakub Kicinski cw.p('/* Common nested types */') 24956afaa0efSJakub Kicinski for attr_set, struct in parsed.pure_nested_structs.items(): 24966f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set) 2497be5bea1cSJakub Kicinski print_type_full(ri, struct) 2498be5bea1cSJakub Kicinski 2499be5bea1cSJakub Kicinski for op_name, op in parsed.ops.items(): 2500be5bea1cSJakub Kicinski cw.p(f"/* ============== {op.enum_name} ============== */") 2501be5bea1cSJakub Kicinski 2502be5bea1cSJakub Kicinski if 'do' in op and 'event' not in op: 2503be5bea1cSJakub Kicinski cw.p(f"/* {op.enum_name} - do */") 25046f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, op, "do") 2505be5bea1cSJakub Kicinski print_req_type(ri) 2506be5bea1cSJakub Kicinski print_req_type_helpers(ri) 2507be5bea1cSJakub Kicinski cw.nl() 2508be5bea1cSJakub Kicinski print_rsp_type(ri) 2509be5bea1cSJakub Kicinski print_rsp_type_helpers(ri) 2510be5bea1cSJakub Kicinski cw.nl() 2511be5bea1cSJakub Kicinski print_req_prototype(ri) 2512be5bea1cSJakub Kicinski cw.nl() 2513be5bea1cSJakub Kicinski 2514be5bea1cSJakub Kicinski if 'dump' in op: 2515be5bea1cSJakub Kicinski cw.p(f"/* {op.enum_name} - dump */") 25166f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, op, 'dump') 2517be5bea1cSJakub Kicinski if 'request' in op['dump']: 2518be5bea1cSJakub Kicinski print_req_type(ri) 2519be5bea1cSJakub Kicinski print_req_type_helpers(ri) 2520be5bea1cSJakub Kicinski if not ri.type_consistent: 2521be5bea1cSJakub Kicinski print_rsp_type(ri) 2522be5bea1cSJakub Kicinski print_wrapped_type(ri) 2523be5bea1cSJakub Kicinski print_dump_prototype(ri) 2524be5bea1cSJakub Kicinski cw.nl() 2525be5bea1cSJakub Kicinski 2526ced15688SJakub Kicinski if op.has_ntf: 2527be5bea1cSJakub Kicinski cw.p(f"/* {op.enum_name} - notify */") 25286f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, op, 'notify') 2529be5bea1cSJakub Kicinski if not ri.type_consistent: 25305605f102SJakub Kicinski raise Exception(f'Only notifications with consistent types supported ({op.name})') 2531be5bea1cSJakub Kicinski print_wrapped_type(ri) 2532be5bea1cSJakub Kicinski 25336da3424fSJakub Kicinski for op_name, op in parsed.ntfs.items(): 2534be5bea1cSJakub Kicinski if 'event' in op: 25356f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, op, 'event') 2536be5bea1cSJakub Kicinski cw.p(f"/* {op.enum_name} - event */") 2537be5bea1cSJakub Kicinski print_rsp_type(ri) 2538be5bea1cSJakub Kicinski cw.nl() 2539be5bea1cSJakub Kicinski print_wrapped_type(ri) 2540be5bea1cSJakub Kicinski cw.nl() 2541be5bea1cSJakub Kicinski else: 254221b6e302SJakub Kicinski cw.p('/* Enums */') 254321b6e302SJakub Kicinski put_op_name(parsed, cw) 254421b6e302SJakub Kicinski 254521b6e302SJakub Kicinski for name, const in parsed.consts.items(): 254621b6e302SJakub Kicinski if isinstance(const, EnumSet): 254721b6e302SJakub Kicinski put_enum_to_str(parsed, cw, const) 254821b6e302SJakub Kicinski cw.nl() 254921b6e302SJakub Kicinski 2550be5bea1cSJakub Kicinski cw.p('/* Policies */') 2551168dea20SJakub Kicinski for name in parsed.pure_nested_structs: 2552be5bea1cSJakub Kicinski struct = Struct(parsed, name) 2553168dea20SJakub Kicinski put_typol(cw, struct) 2554168dea20SJakub Kicinski for name in parsed.root_sets: 2555be5bea1cSJakub Kicinski struct = Struct(parsed, name) 2556be5bea1cSJakub Kicinski put_typol(cw, struct) 2557be5bea1cSJakub Kicinski 2558be5bea1cSJakub Kicinski cw.p('/* Common nested types */') 25596afaa0efSJakub Kicinski for attr_set, struct in parsed.pure_nested_structs.items(): 25606f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set) 2561be5bea1cSJakub Kicinski 2562be5bea1cSJakub Kicinski free_rsp_nested(ri, struct) 2563be5bea1cSJakub Kicinski if struct.request: 2564be5bea1cSJakub Kicinski put_req_nested(ri, struct) 2565be5bea1cSJakub Kicinski if struct.reply: 2566be5bea1cSJakub Kicinski parse_rsp_nested(ri, struct) 2567be5bea1cSJakub Kicinski 2568be5bea1cSJakub Kicinski for op_name, op in parsed.ops.items(): 2569be5bea1cSJakub Kicinski cw.p(f"/* ============== {op.enum_name} ============== */") 2570be5bea1cSJakub Kicinski if 'do' in op and 'event' not in op: 2571be5bea1cSJakub Kicinski cw.p(f"/* {op.enum_name} - do */") 25726f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, op, "do") 25735d58f911SJakub Kicinski print_req_free(ri) 2574be5bea1cSJakub Kicinski print_rsp_free(ri) 2575be5bea1cSJakub Kicinski parse_rsp_msg(ri) 2576be5bea1cSJakub Kicinski print_req(ri) 2577be5bea1cSJakub Kicinski cw.nl() 2578be5bea1cSJakub Kicinski 2579be5bea1cSJakub Kicinski if 'dump' in op: 2580be5bea1cSJakub Kicinski cw.p(f"/* {op.enum_name} - dump */") 25816f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, op, "dump") 2582be5bea1cSJakub Kicinski if not ri.type_consistent: 2583be5bea1cSJakub Kicinski parse_rsp_msg(ri, deref=True) 2584be5bea1cSJakub Kicinski print_dump_type_free(ri) 2585be5bea1cSJakub Kicinski print_dump(ri) 2586be5bea1cSJakub Kicinski cw.nl() 2587be5bea1cSJakub Kicinski 2588ced15688SJakub Kicinski if op.has_ntf: 2589be5bea1cSJakub Kicinski cw.p(f"/* {op.enum_name} - notify */") 25906f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, op, 'notify') 2591be5bea1cSJakub Kicinski if not ri.type_consistent: 25925605f102SJakub Kicinski raise Exception(f'Only notifications with consistent types supported ({op.name})') 2593be5bea1cSJakub Kicinski print_ntf_type_free(ri) 2594be5bea1cSJakub Kicinski 25956da3424fSJakub Kicinski for op_name, op in parsed.ntfs.items(): 2596be5bea1cSJakub Kicinski if 'event' in op: 2597be5bea1cSJakub Kicinski cw.p(f"/* {op.enum_name} - event */") 2598be5bea1cSJakub Kicinski 25996f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, op, "do") 2600be5bea1cSJakub Kicinski parse_rsp_msg(ri) 2601be5bea1cSJakub Kicinski 26026f96ec73SJakub Kicinski ri = RenderInfo(cw, parsed, args.mode, op, "event") 2603be5bea1cSJakub Kicinski print_ntf_type_free(ri) 26048cb6afb3SJakub Kicinski cw.nl() 26058cb6afb3SJakub Kicinski render_user_family(parsed, cw, False) 26068cb6afb3SJakub Kicinski 2607be5bea1cSJakub Kicinski if args.header: 2608be5bea1cSJakub Kicinski cw.p(f'#endif /* {hdr_prot} */') 2609be5bea1cSJakub Kicinski 2610be5bea1cSJakub Kicinski 2611be5bea1cSJakub Kicinskiif __name__ == "__main__": 2612be5bea1cSJakub Kicinski main() 2613