tools: ynl-gen: support fixed headers in genetlink
authorJakub Kicinski <kuba@kernel.org>
Wed, 13 Dec 2023 23:14:27 +0000 (15:14 -0800)
committerJakub Kicinski <kuba@kernel.org>
Fri, 15 Dec 2023 01:51:21 +0000 (17:51 -0800)
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: Donald Hunter <donald.hunter@gmail.com>
Link: https://lore.kernel.org/r/20231213231432.2944749-4-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
tools/net/ynl/lib/ynl.c
tools/net/ynl/lib/ynl.h
tools/net/ynl/ynl-gen-c.py

index 587286de10b559a040e4068c7eee8a31274a1a21..c82a7f41b31c571c09c3dd454a7db3ebbb8a1e60 100644 (file)
@@ -191,12 +191,12 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
                             str ? " (" : "");
 
                start = mnl_nlmsg_get_payload_offset(ys->nlh,
-                                                    sizeof(struct genlmsghdr));
+                                                    ys->family->hdr_len);
                end = mnl_nlmsg_get_payload_tail(ys->nlh);
 
                off = ys->err.attr_offs;
                off -= sizeof(struct nlmsghdr);
-               off -= sizeof(struct genlmsghdr);
+               off -= ys->family->hdr_len;
 
                n += ynl_err_walk(ys, start, end, off, ys->req_policy,
                                  &bad_attr[n], sizeof(bad_attr) - n, NULL);
@@ -217,14 +217,14 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
                             bad_attr[0] ? ", " : (str ? " (" : ""));
 
                start = mnl_nlmsg_get_payload_offset(ys->nlh,
-                                                    sizeof(struct genlmsghdr));
+                                                    ys->family->hdr_len);
                end = mnl_nlmsg_get_payload_tail(ys->nlh);
 
                nest_pol = ys->req_policy;
                if (tb[NLMSGERR_ATTR_MISS_NEST]) {
                        off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]);
                        off -= sizeof(struct nlmsghdr);
-                       off -= sizeof(struct genlmsghdr);
+                       off -= ys->family->hdr_len;
 
                        n += ynl_err_walk(ys, start, end, off, ys->req_policy,
                                          &miss_attr[n], sizeof(miss_attr) - n,
index 5de580b992b8b59524c650513fd5270bcfb582a9..ce77a6d76ce08903640c2c3c16913a031a52b79d 100644 (file)
@@ -44,6 +44,7 @@ struct ynl_error {
 struct ynl_family {
 /* private: */
        const char *name;
+       size_t hdr_len;
        const struct ynl_ntf_info *ntf_info;
        unsigned int ntf_info_size;
 };
index ab009d0f9db509a099d289fa7ca90e8f0610f992..70e2c41e5bd624b81367b1446630c4883b8b8221 100755 (executable)
@@ -1124,6 +1124,10 @@ class RenderInfo:
         self.op_mode = op_mode
         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
         self.type_consistent = True
         if op_mode != 'do' and 'dump' in op:
@@ -1570,7 +1574,9 @@ def _multi_parse(ri, struct, init_lines, local_vars):
     if struct.nested:
         iter_line = "mnl_attr_for_each_nested(attr, nested)"
     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()
     multi_attrs = set()
@@ -1603,6 +1609,9 @@ def _multi_parse(ri, struct, init_lines, local_vars):
     for arg in struct.inherited:
         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):
         aspec = struct[anest]
         ri.cw.p(f"if (dst->{aspec.c_name})")
@@ -1723,6 +1732,10 @@ def print_req(ri):
         ret_err = 'NULL'
         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)
     ri.cw.block_start()
     ri.cw.write_func_lvar(local_vars)
@@ -1733,6 +1746,13 @@ def print_req(ri):
     if 'reply' in ri.op[ri.op_mode]:
         ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
     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():
         attr.attr_put(ri, "req")
     ri.cw.nl()
@@ -1773,9 +1793,11 @@ def print_dump(ri):
                   'struct nlmsghdr *nlh;',
                   'int err;']
 
-    for var in local_vars:
-        ri.cw.p(f'{var}')
-    ri.cw.nl()
+    if ri.fixed_hdr:
+        local_vars += ['size_t hdr_len;',
+                       'void *hdr;']
+
+    ri.cw.write_func_lvar(local_vars)
 
     ri.cw.p('yds.ys = ys;')
     ri.cw.p(f"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});")
@@ -1788,6 +1810,12 @@ def print_dump(ri):
     ri.cw.nl()
     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]:
         ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;")
         ri.cw.nl()
@@ -1845,6 +1873,10 @@ def _print_type(ri, direction, struct):
 
     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
     for _, attr in struct.member_list():
         for type_filter in ['len', 'bit']:
@@ -2482,6 +2514,10 @@ def render_user_family(family, cw, prototype):
 
     cw.block_start(f'{symbol} = ')
     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:
         cw.p(f".ntf_info\t= {family['name']}_ntf_info,")
         cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),")