Commit f6805072 authored by Jakub Kicinski's avatar Jakub Kicinski

tools: ynl-gen: support fixed headers in genetlink

Support genetlink families using simple fixed headers.
Assume fixed header is identical for all ops of the family for now.

Fixed headers are added to the request and reply structs as a _hdr
member, and copied to/from netlink messages appropriately.
Reviewed-by: default avatarDonald Hunter <donald.hunter@gmail.com>
Link: https://lore.kernel.org/r/20231213231432.2944749-4-kuba@kernel.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 139c163b
...@@ -191,12 +191,12 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, ...@@ -191,12 +191,12 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
str ? " (" : ""); str ? " (" : "");
start = mnl_nlmsg_get_payload_offset(ys->nlh, start = mnl_nlmsg_get_payload_offset(ys->nlh,
sizeof(struct genlmsghdr)); ys->family->hdr_len);
end = mnl_nlmsg_get_payload_tail(ys->nlh); end = mnl_nlmsg_get_payload_tail(ys->nlh);
off = ys->err.attr_offs; off = ys->err.attr_offs;
off -= sizeof(struct nlmsghdr); off -= sizeof(struct nlmsghdr);
off -= sizeof(struct genlmsghdr); off -= ys->family->hdr_len;
n += ynl_err_walk(ys, start, end, off, ys->req_policy, n += ynl_err_walk(ys, start, end, off, ys->req_policy,
&bad_attr[n], sizeof(bad_attr) - n, NULL); &bad_attr[n], sizeof(bad_attr) - n, NULL);
...@@ -217,14 +217,14 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, ...@@ -217,14 +217,14 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
bad_attr[0] ? ", " : (str ? " (" : "")); bad_attr[0] ? ", " : (str ? " (" : ""));
start = mnl_nlmsg_get_payload_offset(ys->nlh, start = mnl_nlmsg_get_payload_offset(ys->nlh,
sizeof(struct genlmsghdr)); ys->family->hdr_len);
end = mnl_nlmsg_get_payload_tail(ys->nlh); end = mnl_nlmsg_get_payload_tail(ys->nlh);
nest_pol = ys->req_policy; nest_pol = ys->req_policy;
if (tb[NLMSGERR_ATTR_MISS_NEST]) { if (tb[NLMSGERR_ATTR_MISS_NEST]) {
off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]); off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]);
off -= sizeof(struct nlmsghdr); off -= sizeof(struct nlmsghdr);
off -= sizeof(struct genlmsghdr); off -= ys->family->hdr_len;
n += ynl_err_walk(ys, start, end, off, ys->req_policy, n += ynl_err_walk(ys, start, end, off, ys->req_policy,
&miss_attr[n], sizeof(miss_attr) - n, &miss_attr[n], sizeof(miss_attr) - n,
......
...@@ -44,6 +44,7 @@ struct ynl_error { ...@@ -44,6 +44,7 @@ struct ynl_error {
struct ynl_family { struct ynl_family {
/* private: */ /* private: */
const char *name; const char *name;
size_t hdr_len;
const struct ynl_ntf_info *ntf_info; const struct ynl_ntf_info *ntf_info;
unsigned int ntf_info_size; unsigned int ntf_info_size;
}; };
......
...@@ -1124,6 +1124,10 @@ class RenderInfo: ...@@ -1124,6 +1124,10 @@ class RenderInfo:
self.op_mode = op_mode self.op_mode = op_mode
self.op = op self.op = op
self.fixed_hdr = None
if op and op.fixed_header:
self.fixed_hdr = 'struct ' + c_lower(op.fixed_header)
# 'do' and 'dump' response parsing is identical # 'do' and 'dump' response parsing is identical
self.type_consistent = True self.type_consistent = True
if op_mode != 'do' and 'dump' in op: if op_mode != 'do' and 'dump' in op:
...@@ -1570,7 +1574,9 @@ def _multi_parse(ri, struct, init_lines, local_vars): ...@@ -1570,7 +1574,9 @@ def _multi_parse(ri, struct, init_lines, local_vars):
if struct.nested: if struct.nested:
iter_line = "mnl_attr_for_each_nested(attr, nested)" iter_line = "mnl_attr_for_each_nested(attr, nested)"
else: else:
iter_line = "mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr))" if ri.fixed_hdr:
local_vars += ['void *hdr;']
iter_line = "mnl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len)"
array_nests = set() array_nests = set()
multi_attrs = set() multi_attrs = set()
...@@ -1603,6 +1609,9 @@ def _multi_parse(ri, struct, init_lines, local_vars): ...@@ -1603,6 +1609,9 @@ def _multi_parse(ri, struct, init_lines, local_vars):
for arg in struct.inherited: for arg in struct.inherited:
ri.cw.p(f'dst->{arg} = {arg};') ri.cw.p(f'dst->{arg} = {arg};')
if ri.fixed_hdr:
ri.cw.p('hdr = mnl_nlmsg_get_payload_offset(nlh, sizeof(struct genlmsghdr));')
ri.cw.p(f"memcpy(&dst->_hdr, hdr, sizeof({ri.fixed_hdr}));")
for anest in sorted(all_multi): for anest in sorted(all_multi):
aspec = struct[anest] aspec = struct[anest]
ri.cw.p(f"if (dst->{aspec.c_name})") ri.cw.p(f"if (dst->{aspec.c_name})")
...@@ -1723,6 +1732,10 @@ def print_req(ri): ...@@ -1723,6 +1732,10 @@ def print_req(ri):
ret_err = 'NULL' ret_err = 'NULL'
local_vars += [f'{type_name(ri, rdir(direction))} *rsp;'] local_vars += [f'{type_name(ri, rdir(direction))} *rsp;']
if ri.fixed_hdr:
local_vars += ['size_t hdr_len;',
'void *hdr;']
print_prototype(ri, direction, terminate=False) print_prototype(ri, direction, terminate=False)
ri.cw.block_start() ri.cw.block_start()
ri.cw.write_func_lvar(local_vars) ri.cw.write_func_lvar(local_vars)
...@@ -1733,6 +1746,13 @@ def print_req(ri): ...@@ -1733,6 +1746,13 @@ def print_req(ri):
if 'reply' in ri.op[ri.op_mode]: if 'reply' in ri.op[ri.op_mode]:
ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
ri.cw.nl() ri.cw.nl()
if ri.fixed_hdr:
ri.cw.p("hdr_len = sizeof(req->_hdr);")
ri.cw.p("hdr = mnl_nlmsg_put_extra_header(nlh, hdr_len);")
ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);")
ri.cw.nl()
for _, attr in ri.struct["request"].member_list(): for _, attr in ri.struct["request"].member_list():
attr.attr_put(ri, "req") attr.attr_put(ri, "req")
ri.cw.nl() ri.cw.nl()
...@@ -1773,9 +1793,11 @@ def print_dump(ri): ...@@ -1773,9 +1793,11 @@ def print_dump(ri):
'struct nlmsghdr *nlh;', 'struct nlmsghdr *nlh;',
'int err;'] 'int err;']
for var in local_vars: if ri.fixed_hdr:
ri.cw.p(f'{var}') local_vars += ['size_t hdr_len;',
ri.cw.nl() 'void *hdr;']
ri.cw.write_func_lvar(local_vars)
ri.cw.p('yds.ys = ys;') ri.cw.p('yds.ys = ys;')
ri.cw.p(f"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});") ri.cw.p(f"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});")
...@@ -1788,6 +1810,12 @@ def print_dump(ri): ...@@ -1788,6 +1810,12 @@ def print_dump(ri):
ri.cw.nl() ri.cw.nl()
ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
if ri.fixed_hdr:
ri.cw.p("hdr_len = sizeof(req->_hdr);")
ri.cw.p("hdr = mnl_nlmsg_put_extra_header(nlh, hdr_len);")
ri.cw.p("memcpy(hdr, &req->_hdr, hdr_len);")
ri.cw.nl()
if "request" in ri.op[ri.op_mode]: if "request" in ri.op[ri.op_mode]:
ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;") ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;")
ri.cw.nl() ri.cw.nl()
...@@ -1845,6 +1873,10 @@ def _print_type(ri, direction, struct): ...@@ -1845,6 +1873,10 @@ def _print_type(ri, direction, struct):
ri.cw.block_start(line=f"struct {ri.family.c_name}{suffix}") ri.cw.block_start(line=f"struct {ri.family.c_name}{suffix}")
if ri.fixed_hdr:
ri.cw.p(ri.fixed_hdr + ' _hdr;')
ri.cw.nl()
meta_started = False meta_started = False
for _, attr in struct.member_list(): for _, attr in struct.member_list():
for type_filter in ['len', 'bit']: for type_filter in ['len', 'bit']:
...@@ -2482,6 +2514,10 @@ def render_user_family(family, cw, prototype): ...@@ -2482,6 +2514,10 @@ def render_user_family(family, cw, prototype):
cw.block_start(f'{symbol} = ') cw.block_start(f'{symbol} = ')
cw.p(f'.name\t\t= "{family.c_name}",') cw.p(f'.name\t\t= "{family.c_name}",')
if family.fixed_header:
cw.p(f'.hdr_len\t= sizeof(struct genlmsghdr) + sizeof(struct {c_lower(family.fixed_header)}),')
else:
cw.p('.hdr_len\t= sizeof(struct genlmsghdr),')
if family.ntfs: if family.ntfs:
cw.p(f".ntf_info\t= {family['name']}_ntf_info,") 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.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment