libbpf: Skip zeroed or null fields if not found in the kernel type.
authorKui-Feng Lee <thinker.li@gmail.com>
Wed, 13 Mar 2024 21:41:37 +0000 (14:41 -0700)
committerAndrii Nakryiko <andrii@kernel.org>
Thu, 14 Mar 2024 20:47:05 +0000 (13:47 -0700)
Accept additional fields of a struct_ops type with all zero values even if
these fields are not in the corresponding type in the kernel. This provides
a way to be backward compatible. User space programs can use the same map
on a machine running an old kernel by clearing fields that do not exist in
the kernel.

Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20240313214139.685112-2-thinker.li@gmail.com
tools/lib/bpf/libbpf.c

index 124883eaa0cfdb6bf0665c7c1e4f73cc895bfc51..604368cfbf029a5b5e7216908f52e05c15507fef 100644 (file)
@@ -1132,8 +1132,26 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map)
                const char *mname;
 
                mname = btf__name_by_offset(btf, member->name_off);
+               moff = member->offset / 8;
+               mdata = data + moff;
+               msize = btf__resolve_size(btf, member->type);
+               if (msize < 0) {
+                       pr_warn("struct_ops init_kern %s: failed to resolve the size of member %s\n",
+                               map->name, mname);
+                       return msize;
+               }
+
                kern_member = find_member_by_name(kern_btf, kern_type, mname);
                if (!kern_member) {
+                       /* Skip all zeros or null fields if they are not
+                        * presented in the kernel BTF.
+                        */
+                       if (libbpf_is_mem_zeroed(mdata, msize)) {
+                               pr_info("struct_ops %s: member %s not found in kernel, skipping it as it's set to zero\n",
+                                       map->name, mname);
+                               continue;
+                       }
+
                        pr_warn("struct_ops init_kern %s: Cannot find member %s in kernel BTF\n",
                                map->name, mname);
                        return -ENOTSUP;
@@ -1147,10 +1165,7 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map)
                        return -ENOTSUP;
                }
 
-               moff = member->offset / 8;
                kern_moff = kern_member->offset / 8;
-
-               mdata = data + moff;
                kern_mdata = kern_data + kern_moff;
 
                mtype = skip_mods_and_typedefs(btf, member->type, &mtype_id);
@@ -1230,9 +1245,8 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map)
                        continue;
                }
 
-               msize = btf__resolve_size(btf, mtype_id);
                kern_msize = btf__resolve_size(kern_btf, kern_mtype_id);
-               if (msize < 0 || kern_msize < 0 || msize != kern_msize) {
+               if (kern_msize < 0 || msize != kern_msize) {
                        pr_warn("struct_ops init_kern %s: Error in size of member %s: %zd != %zd(kernel)\n",
                                map->name, mname, (ssize_t)msize,
                                (ssize_t)kern_msize);