]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
tools: ynl: allow fixed-header to be specified per op
authorJakub Kicinski <kuba@kernel.org>
Tue, 29 Apr 2025 15:47:04 +0000 (08:47 -0700)
committerPaolo Abeni <pabeni@redhat.com>
Fri, 2 May 2025 10:41:03 +0000 (12:41 +0200)
rtnetlink has variety of ops with different fixed headers.
Detect that op fixed header is not the same as family one,
and use sizeof() directly. For reverse parsing we need to
pass the fixed header len along the policy (in the socket
state).

Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Link: https://patch.msgid.link/20250429154704.2613851-13-kuba@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
tools/net/ynl/lib/ynl.c
tools/net/ynl/lib/ynl.h
tools/net/ynl/pyynl/ynl_gen_c.py

index c16f01372ca32dc916d07384aef7110d706115f7..d263f6f40ad5777e56ae6aa1e779f5983e4c651c 100644 (file)
@@ -191,12 +191,12 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
                n = snprintf(bad_attr, sizeof(bad_attr), "%sbad attribute: ",
                             str ? " (" : "");
 
-               start = ynl_nlmsg_data_offset(ys->nlh, ys->family->hdr_len);
+               start = ynl_nlmsg_data_offset(ys->nlh, ys->req_hdr_len);
                end = ynl_nlmsg_end_addr(ys->nlh);
 
                off = ys->err.attr_offs;
                off -= sizeof(struct nlmsghdr);
-               off -= ys->family->hdr_len;
+               off -= ys->req_hdr_len;
 
                n += ynl_err_walk(ys, start, end, off, ys->req_policy,
                                  &bad_attr[n], sizeof(bad_attr) - n, NULL);
@@ -216,14 +216,14 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh,
                n = snprintf(miss_attr, sizeof(miss_attr), "%smissing attribute: ",
                             bad_attr[0] ? ", " : (str ? " (" : ""));
 
-               start = ynl_nlmsg_data_offset(ys->nlh, ys->family->hdr_len);
+               start = ynl_nlmsg_data_offset(ys->nlh, ys->req_hdr_len);
                end = ynl_nlmsg_end_addr(ys->nlh);
 
                nest_pol = ys->req_policy;
                if (tb[NLMSGERR_ATTR_MISS_NEST]) {
                        off = ynl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]);
                        off -= sizeof(struct nlmsghdr);
-                       off -= ys->family->hdr_len;
+                       off -= ys->req_hdr_len;
 
                        n += ynl_err_walk(ys, start, end, off, ys->req_policy,
                                          &miss_attr[n], sizeof(miss_attr) - n,
index 6b8a625aaa5ff61f8118bf1e499e25490d3a6870..32efeb224829335bee754e5357e3fe24242d3cca 100644 (file)
@@ -80,6 +80,7 @@ struct ynl_sock {
 
        struct nlmsghdr *nlh;
        const struct ynl_policy_nest *req_policy;
+       size_t req_hdr_len;
        unsigned char *tx_buf;
        unsigned char *rx_buf;
        unsigned char raw_buf[];
index 1dd9580086cd5ecf98216ed0f5f7386e5a4da045..09b87c9a6908174a57ba724b99469e550621399d 100755 (executable)
@@ -1311,8 +1311,15 @@ class RenderInfo:
         self.op = op
 
         self.fixed_hdr = None
+        self.fixed_hdr_len = 'ys->family->hdr_len'
         if op and op.fixed_header:
             self.fixed_hdr = 'struct ' + c_lower(op.fixed_header)
+            if op.fixed_header != family.fixed_header:
+                if family.is_classic():
+                    self.fixed_hdr_len = f"sizeof({self.fixed_hdr})"
+                else:
+                    raise Exception(f"Per-op fixed header not supported, yet")
+
 
         # 'do' and 'dump' response parsing is identical
         self.type_consistent = True
@@ -1799,6 +1806,11 @@ def _multi_parse(ri, struct, init_lines, local_vars):
         if ri.fixed_hdr:
             local_vars += ['void *hdr;']
         iter_line = "ynl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len)"
+        if ri.op.fixed_header != ri.family.fixed_header:
+            if ri.family.is_classic():
+                iter_line = f"ynl_attr_for_each(attr, nlh, sizeof({ri.fixed_hdr}))"
+            else:
+                raise Exception(f"Per-op fixed header not supported, yet")
 
     array_nests = set()
     multi_attrs = set()
@@ -2016,6 +2028,7 @@ def print_req(ri):
         ri.cw.p(f"nlh = ynl_gemsg_start_req(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
 
     ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;")
+    ri.cw.p(f"ys->req_hdr_len = {ri.fixed_hdr_len};")
     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()
@@ -2095,6 +2108,7 @@ def print_dump(ri):
 
     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_hdr_len = {ri.fixed_hdr_len};")
         ri.cw.nl()
         for _, attr in ri.struct["request"].member_list():
             attr.attr_put(ri, "req")
@@ -2914,7 +2928,8 @@ def render_user_family(family, cw, prototype):
         cw.p(f'.is_classic\t= true,')
         cw.p(f'.classic_id\t= {family.get("protonum")},')
     if family.is_classic():
-        cw.p(f'.hdr_len\t= sizeof(struct {c_lower(family.fixed_header)}),')
+        if family.fixed_header:
+            cw.p(f'.hdr_len\t= sizeof(struct {c_lower(family.fixed_header)}),')
     elif family.fixed_header:
         cw.p(f'.hdr_len\t= sizeof(struct genlmsghdr) + sizeof(struct {c_lower(family.fixed_header)}),')
     else: