summaryrefslogtreecommitdiff
path: root/tools/net/ynl/ynl-gen-c.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/net/ynl/ynl-gen-c.py')
-rwxr-xr-xtools/net/ynl/ynl-gen-c.py253
1 files changed, 110 insertions, 143 deletions
diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py
index 251c5bfffd8d..7b051c00cfc3 100755
--- a/tools/net/ynl/ynl-gen-c.py
+++ b/tools/net/ynl/ynl-gen-c.py
@@ -153,7 +153,7 @@ class Type(SpecAttr):
init_lines = [init_lines]
kw = 'if' if first else 'else if'
- ri.cw.block_start(line=f"{kw} (mnl_attr_get_type(attr) == {self.enum_name})")
+ ri.cw.block_start(line=f"{kw} (type == {self.enum_name})")
if local_vars:
for local in local_vars:
ri.cw.p(local)
@@ -227,12 +227,18 @@ class TypePad(Type):
def _attr_typol(self):
return '.type = YNL_PT_IGNORE, '
+ def attr_put(self, ri, var):
+ pass
+
def attr_get(self, ri, var, first):
pass
def attr_policy(self, cw):
pass
+ def setter(self, ri, space, direction, deref=False, ref=None):
+ pass
+
class TypeScalar(Type):
def __init__(self, family, attr_set, attr, value):
@@ -714,6 +720,8 @@ class Operation(SpecOperation):
self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \
('dump' in yaml and 'request' in yaml['dump'])
+ self.has_ntf = False
+
# Added by resolve:
self.enum_name = None
delattr(self, "enum_name")
@@ -726,12 +734,8 @@ class Operation(SpecOperation):
else:
self.enum_name = self.family.async_op_prefix + c_upper(self.name)
- def add_notification(self, op):
- if 'notify' not in self.yaml:
- self.yaml['notify'] = dict()
- self.yaml['notify']['reply'] = self.yaml['do']['reply']
- self.yaml['notify']['cmds'] = []
- self.yaml['notify']['cmds'].append(op)
+ def mark_has_ntf(self):
+ self.has_ntf = True
class Family(SpecFamily):
@@ -793,14 +797,12 @@ class Family(SpecFamily):
self.root_sets = dict()
# dict space-name -> set('request', 'reply')
self.pure_nested_structs = dict()
- self.all_notify = dict()
+ self._mark_notify()
self._mock_up_events()
- self._dictify()
self._load_root_sets()
self._load_nested_sets()
- self._load_all_notify()
self._load_hooks()
self.kernel_policy = self.yaml.get('kernel-policy', 'split')
@@ -816,6 +818,11 @@ class Family(SpecFamily):
def new_operation(self, elem, req_value, rsp_value):
return Operation(self, elem, req_value, rsp_value)
+ def _mark_notify(self):
+ for op in self.msgs.values():
+ if 'notify' in op:
+ self.ops[op['notify']].mark_has_ntf()
+
# Fake a 'do' equivalent of all events, so that we can render their response parsing
def _mock_up_events(self):
for op in self.yaml['operations']['list']:
@@ -826,16 +833,8 @@ class Family(SpecFamily):
}
}
- def _dictify(self):
- ntf = []
- for msg in self.msgs.values():
- if 'notify' in msg:
- ntf.append(msg)
- for n in ntf:
- self.ops[n['notify']].add_notification(n)
-
def _load_root_sets(self):
- for op_name, op in self.ops.items():
+ for op_name, op in self.msgs.items():
if 'attribute-set' not in op:
continue
@@ -846,6 +845,8 @@ class Family(SpecFamily):
req_attrs.update(set(op[op_mode]['request']['attributes']))
if op_mode in op and 'reply' in op[op_mode]:
rsp_attrs.update(set(op[op_mode]['reply']['attributes']))
+ if 'event' in op:
+ rsp_attrs.update(set(op['event']['attributes']))
if op['attribute-set'] not in self.root_sets:
self.root_sets[op['attribute-set']] = {'request': req_attrs, 'reply': rsp_attrs}
@@ -922,14 +923,6 @@ class Family(SpecFamily):
child.request |= struct.request
child.reply |= struct.reply
- def _load_all_notify(self):
- for op_name, op in self.ops.items():
- if not op:
- continue
-
- if 'notify' in op:
- self.all_notify[op_name] = op['notify']['cmds']
-
def _load_global_policy(self):
global_set = set()
attr_set_name = None
@@ -968,21 +961,14 @@ class Family(SpecFamily):
self.hooks[when][op_mode]['set'].add(name)
self.hooks[when][op_mode]['list'].append(name)
- def has_notifications(self):
- for op in self.ops.values():
- if 'notify' in op or 'event' in op:
- return True
- return False
-
class RenderInfo:
- def __init__(self, cw, family, ku_space, op, op_name, op_mode, attr_set=None):
+ def __init__(self, cw, family, ku_space, op, op_mode, attr_set=None):
self.family = family
self.nl = cw.nlib
self.ku_space = ku_space
- self.op = op
- self.op_name = op_name
self.op_mode = op_mode
+ self.op = op
# 'do' and 'dump' response parsing is identical
self.type_consistent = True
@@ -997,13 +983,15 @@ class RenderInfo:
self.attr_set = op['attribute-set']
if op:
- self.type_name = c_lower(op_name)
+ self.type_name = c_lower(op.name)
else:
self.type_name = c_lower(attr_set)
self.cw = cw
self.struct = dict()
+ if op_mode == 'notify':
+ op_mode = 'do'
for op_dir in ['request', 'reply']:
if op and op_dir in op[op_mode]:
self.struct[op_dir] = Struct(family, self.attr_set,
@@ -1017,6 +1005,7 @@ class CodeWriter:
self.nlib = nlib
self._nl = False
+ self._block_end = False
self._silent_block = False
self._ind = 0
self._out = out_file
@@ -1025,11 +1014,18 @@ class CodeWriter:
def _is_cond(cls, line):
return line.startswith('if') or line.startswith('while') or line.startswith('for')
- def p(self, line, add_ind=0, eat_nl=False):
+ def p(self, line, add_ind=0):
+ if self._block_end:
+ self._block_end = False
+ if line.startswith('else'):
+ line = '} ' + line
+ else:
+ self._out.write('\t' * self._ind + '}\n')
+
if self._nl:
- if not eat_nl:
- self._out.write('\n')
+ self._out.write('\n')
self._nl = False
+
ind = self._ind
if line[-1] == ':':
ind -= 1
@@ -1053,7 +1049,14 @@ class CodeWriter:
if line and line[0] not in {';', ','}:
line = ' ' + line
self._ind -= 1
- self.p('}' + line, eat_nl=True)
+ self._nl = False
+ if not line:
+ # Delay printing closing bracket in case "else" comes next
+ if self._block_end:
+ self._out.write('\t' * (self._ind + 1) + '}\n')
+ self._block_end = True
+ else:
+ self.p('}' + line)
def write_doc_line(self, doc, indent=True):
words = doc.split()
@@ -1172,7 +1175,40 @@ op_mode_to_wrapper = {
}
_C_KW = {
- 'do'
+ 'auto',
+ 'bool',
+ 'break',
+ 'case',
+ 'char',
+ 'const',
+ 'continue',
+ 'default',
+ 'do',
+ 'double',
+ 'else',
+ 'enum',
+ 'extern',
+ 'float',
+ 'for',
+ 'goto',
+ 'if',
+ 'inline',
+ 'int',
+ 'long',
+ 'register',
+ 'return',
+ 'short',
+ 'signed',
+ 'sizeof',
+ 'static',
+ 'struct',
+ 'switch',
+ 'typedef',
+ 'union',
+ 'unsigned',
+ 'void',
+ 'volatile',
+ 'while'
}
@@ -1370,6 +1406,8 @@ def _multi_parse(ri, struct, init_lines, local_vars):
ri.cw.nl()
ri.cw.block_start(line=iter_line)
+ ri.cw.p('unsigned int type = mnl_attr_get_type(attr);')
+ ri.cw.nl()
first = True
for _, arg in struct.member_list():
@@ -1760,70 +1798,6 @@ def print_ntf_type_free(ri):
ri.cw.nl()
-def print_ntf_parse_prototype(family, cw, suffix=';'):
- cw.write_func_prot('struct ynl_ntf_base_type *', f"{family['name']}_ntf_parse",
- ['struct ynl_sock *ys'], suffix=suffix)
-
-
-def print_ntf_type_parse(family, cw, ku_mode):
- print_ntf_parse_prototype(family, cw, suffix='')
- cw.block_start()
- cw.write_func_lvar(['struct genlmsghdr *genlh;',
- 'struct nlmsghdr *nlh;',
- 'struct ynl_parse_arg yarg = { .ys = ys, };',
- 'struct ynl_ntf_base_type *rsp;',
- 'int len, err;',
- 'mnl_cb_t parse;'])
- cw.p('len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);')
- cw.p('if (len < (ssize_t)(sizeof(*nlh) + sizeof(*genlh)))')
- cw.p('return NULL;')
- cw.nl()
- cw.p('nlh = (struct nlmsghdr *)ys->rx_buf;')
- cw.p('genlh = mnl_nlmsg_get_payload(nlh);')
- cw.nl()
- cw.block_start(line='switch (genlh->cmd)')
- for ntf_op in sorted(family.all_notify.keys()):
- op = family.ops[ntf_op]
- ri = RenderInfo(cw, family, ku_mode, op, ntf_op, "notify")
- for ntf in op['notify']['cmds']:
- cw.p(f"case {ntf.enum_name}:")
- cw.p(f"rsp = calloc(1, sizeof({type_name(ri, 'notify')}));")
- cw.p(f"parse = {op_prefix(ri, 'reply', deref=True)}_parse;")
- cw.p(f"yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
- cw.p(f"rsp->free = (void *){op_prefix(ri, 'notify')}_free;")
- cw.p('break;')
- for op_name, op in family.ops.items():
- if 'event' not in op:
- continue
- ri = RenderInfo(cw, family, ku_mode, op, op_name, "event")
- cw.p(f"case {op.enum_name}:")
- cw.p(f"rsp = calloc(1, sizeof({type_name(ri, 'event')}));")
- cw.p(f"parse = {op_prefix(ri, 'reply', deref=True)}_parse;")
- cw.p(f"yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
- cw.p(f"rsp->free = (void *){op_prefix(ri, 'notify')}_free;")
- cw.p('break;')
- cw.p('default:')
- cw.p('ynl_error_unknown_notification(ys, genlh->cmd);')
- cw.p('return NULL;')
- cw.block_end()
- cw.nl()
- cw.p('yarg.data = rsp->data;')
- cw.nl()
- cw.p(f"err = {cw.nlib.parse_cb_run('parse', '&yarg', True)};")
- cw.p('if (err < 0)')
- cw.p('goto err_free;')
- cw.nl()
- cw.p('rsp->family = nlh->nlmsg_type;')
- cw.p('rsp->cmd = genlh->cmd;')
- cw.p('return rsp;')
- cw.nl()
- cw.p('err_free:')
- cw.p('free(rsp);')
- cw.p('return NULL;')
- cw.block_end()
- cw.nl()
-
-
def print_req_policy_fwd(cw, struct, ri=None, terminate=True):
if terminate and ri and kernel_can_gen_family_struct(struct.family):
return
@@ -2223,25 +2197,28 @@ def render_user_family(family, cw, prototype):
cw.p(f'extern {symbol};')
return
- ntf = family.has_notifications()
- if ntf:
+ if family.ntfs:
cw.block_start(line=f"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ")
- for ntf_op in sorted(family.all_notify.keys()):
- op = family.ops[ntf_op]
- ri = RenderInfo(cw, family, "user", op, ntf_op, "notify")
- for ntf in op['notify']['cmds']:
- _render_user_ntf_entry(ri, ntf)
+ for ntf_op_name, ntf_op in family.ntfs.items():
+ if 'notify' in ntf_op:
+ op = family.ops[ntf_op['notify']]
+ ri = RenderInfo(cw, family, "user", op, "notify")
+ elif 'event' in ntf_op:
+ ri = RenderInfo(cw, family, "user", ntf_op, "event")
+ else:
+ raise Exception('Invalid notification ' + ntf_op_name)
+ _render_user_ntf_entry(ri, ntf_op)
for op_name, op in family.ops.items():
if 'event' not in op:
continue
- ri = RenderInfo(cw, family, "user", op, op_name, "event")
+ ri = RenderInfo(cw, family, "user", op, "event")
_render_user_ntf_entry(ri, op)
cw.block_end(line=";")
cw.nl()
cw.block_start(f'{symbol} = ')
cw.p(f'.name\t\t= "{family.name}",')
- if ntf:
+ if family.ntfs:
cw.p(f".ntf_info\t= {family['name']}_ntf_info,")
cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),")
cw.block_end(line=';')
@@ -2323,8 +2300,8 @@ def main():
headers = ['uapi/' + parsed.uapi_header]
else:
cw.p('#include <stdlib.h>')
+ cw.p('#include <string.h>')
if args.header:
- cw.p('#include <string.h>')
cw.p('#include <linux/types.h>')
else:
cw.p(f'#include "{parsed.name}-user.h"')
@@ -2339,9 +2316,6 @@ def main():
if args.mode == "user":
if not args.header:
- cw.p("#include <stdlib.h>")
- cw.p("#include <stdio.h>")
- cw.p("#include <string.h>")
cw.p("#include <libmnl/libmnl.h>")
cw.p("#include <linux/genetlink.h>")
cw.nl()
@@ -2374,7 +2348,7 @@ def main():
if parsed.kernel_policy in {'per-op', 'split'}:
for op_name, op in parsed.ops.items():
if 'do' in op and 'event' not in op:
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do")
+ ri = RenderInfo(cw, parsed, args.mode, op, "do")
print_req_policy_fwd(cw, ri.struct['request'], ri=ri)
cw.nl()
@@ -2403,7 +2377,7 @@ def main():
for op_mode in ['do', 'dump']:
if op_mode in op and 'request' in op[op_mode]:
cw.p(f"/* {op.enum_name} - {op_mode} */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, op_mode)
+ ri = RenderInfo(cw, parsed, args.mode, op, op_mode)
print_req_policy(cw, ri.struct['request'], ri=ri)
cw.nl()
@@ -2423,7 +2397,7 @@ def main():
cw.p('/* Common nested types */')
for attr_set, struct in parsed.pure_nested_structs.items():
- ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set)
+ ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set)
print_type_full(ri, struct)
for op_name, op in parsed.ops.items():
@@ -2431,7 +2405,7 @@ def main():
if 'do' in op and 'event' not in op:
cw.p(f"/* {op.enum_name} - do */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do")
+ ri = RenderInfo(cw, parsed, args.mode, op, "do")
print_req_type(ri)
print_req_type_helpers(ri)
cw.nl()
@@ -2443,7 +2417,7 @@ def main():
if 'dump' in op:
cw.p(f"/* {op.enum_name} - dump */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'dump')
+ ri = RenderInfo(cw, parsed, args.mode, op, 'dump')
if 'request' in op['dump']:
print_req_type(ri)
print_req_type_helpers(ri)
@@ -2453,23 +2427,20 @@ def main():
print_dump_prototype(ri)
cw.nl()
- if 'notify' in op:
+ if op.has_ntf:
cw.p(f"/* {op.enum_name} - notify */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify')
+ ri = RenderInfo(cw, parsed, args.mode, op, 'notify')
if not ri.type_consistent:
raise Exception(f'Only notifications with consistent types supported ({op.name})')
print_wrapped_type(ri)
+ for op_name, op in parsed.ntfs.items():
if 'event' in op:
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'event')
+ ri = RenderInfo(cw, parsed, args.mode, op, 'event')
cw.p(f"/* {op.enum_name} - event */")
print_rsp_type(ri)
cw.nl()
print_wrapped_type(ri)
-
- if parsed.has_notifications():
- cw.p('/* --------------- Common notification parsing --------------- */')
- print_ntf_parse_prototype(parsed, cw)
cw.nl()
else:
cw.p('/* Enums */')
@@ -2490,7 +2461,7 @@ def main():
cw.p('/* Common nested types */')
for attr_set, struct in parsed.pure_nested_structs.items():
- ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set)
+ ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set)
free_rsp_nested(ri, struct)
if struct.request:
@@ -2502,7 +2473,7 @@ def main():
cw.p(f"/* ============== {op.enum_name} ============== */")
if 'do' in op and 'event' not in op:
cw.p(f"/* {op.enum_name} - do */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do")
+ ri = RenderInfo(cw, parsed, args.mode, op, "do")
print_req_free(ri)
print_rsp_free(ri)
parse_rsp_msg(ri)
@@ -2511,33 +2482,29 @@ def main():
if 'dump' in op:
cw.p(f"/* {op.enum_name} - dump */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "dump")
+ ri = RenderInfo(cw, parsed, args.mode, op, "dump")
if not ri.type_consistent:
parse_rsp_msg(ri, deref=True)
print_dump_type_free(ri)
print_dump(ri)
cw.nl()
- if 'notify' in op:
+ if op.has_ntf:
cw.p(f"/* {op.enum_name} - notify */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify')
+ ri = RenderInfo(cw, parsed, args.mode, op, 'notify')
if not ri.type_consistent:
raise Exception(f'Only notifications with consistent types supported ({op.name})')
print_ntf_type_free(ri)
+ for op_name, op in parsed.ntfs.items():
if 'event' in op:
cw.p(f"/* {op.enum_name} - event */")
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do")
+ ri = RenderInfo(cw, parsed, args.mode, op, "do")
parse_rsp_msg(ri)
- ri = RenderInfo(cw, parsed, args.mode, op, op_name, "event")
+ ri = RenderInfo(cw, parsed, args.mode, op, "event")
print_ntf_type_free(ri)
-
- if parsed.has_notifications():
- cw.p('/* --------------- Common notification parsing --------------- */')
- print_ntf_type_parse(parsed, cw, args.mode)
-
cw.nl()
render_user_family(parsed, cw, False)