Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpf: support resilient split BTF #7196

Closed

Conversation

kernel-patches-daemon-bpf[bot]
Copy link

Pull request for series with
subject: bpf: support resilient split BTF
version: 6
url: https://patchwork.kernel.org/project/netdevbpf/list/?series=861557

@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: 4ff5747
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=861557
version: 6

@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: 4ff5747
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=861557
version: 6

@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: 041c1dc
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=861557
version: 6

@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: 373a4e1
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=861557
version: 6

@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: cdbde08
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=861557
version: 6

alan-maguire and others added 7 commits June 14, 2024 12:55
…e BTF

To support more robust split BTF, adding supplemental context for the
base BTF type ids that split BTF refers to is required.  Without such
references, a simple shuffling of base BTF type ids (without any other
significant change) invalidates the split BTF.  Here the attempt is made
to store additional context to make split BTF more robust.

This context comes in the form of distilled base BTF providing minimal
information (name and - in some cases - size) for base INTs, FLOATs,
STRUCTs, UNIONs, ENUMs and ENUM64s along with modified split BTF that
points at that base and contains any additional types needed (such as
TYPEDEF, PTR and anonymous STRUCT/UNION declarations).  This
information constitutes the minimal BTF representation needed to
disambiguate or remove split BTF references to base BTF.  The rules
are as follows:

- INT, FLOAT, FWD are recorded in full.
- if a named base BTF STRUCT or UNION is referred to from split BTF, it
  will be encoded as a zero-member sized STRUCT/UNION (preserving
  size for later relocation checks).  Only base BTF STRUCT/UNIONs
  that are either embedded in split BTF STRUCT/UNIONs or that have
  multiple STRUCT/UNION instances of the same name will _need_ size
  checks at relocation time, but as it is possible a different set of
  types will be duplicates in the later to-be-resolved base BTF,
  we preserve size information for all named STRUCT/UNIONs.
- if an ENUM[64] is named, a ENUM forward representation (an ENUM
  with no values) of the same size is used.
- in all other cases, the type is added to the new split BTF.

Avoiding struct/union/enum/enum64 expansion is important to keep the
distilled base BTF representation to a minimum size.

When successful, new representations of the distilled base BTF and new
split BTF that refers to it are returned.  Both need to be freed by the
caller.

So to take a simple example, with split BTF with a type referring
to "struct sk_buff", we will generate distilled base BTF with a
0-member STRUCT sk_buff of the appropriate size, and the split BTF
will refer to it instead.

Tools like pahole can utilize such split BTF to populate the .BTF
section (split BTF) and an additional .BTF.base section.  Then
when the split BTF is loaded, the distilled base BTF can be used
to relocate split BTF to reference the current (and possibly changed)
base BTF.

So for example if "struct sk_buff" was id 502 when the split BTF was
originally generated,  we can use the distilled base BTF to see that
id 502 refers to a "struct sk_buff" and replace instances of id 502
with the current (relocated) base BTF sk_buff type id.

Distilled base BTF is small; when building a kernel with all modules
using distilled base BTF as a test, overall module size grew by only
5.3Mb total across ~2700 modules.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Test generation of split+distilled base BTF, ensuring that

- named base BTF STRUCTs and UNIONs are represented as 0-vlen sized
  STRUCT/UNIONs
- named ENUM[64]s are represented as 0-vlen named ENUM[64]s
- anonymous struct/unions are represented in full in split BTF
- anonymous enums are represented in full in split BTF
- types unreferenced from split BTF are not present in distilled
  base BTF

Also test that with vmlinux BTF and split BTF based upon it,
we only represent needed base types referenced from split BTF
in distilled base.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Map distilled base BTF type ids referenced in split BTF and their
references to the base BTF passed in, and if the mapping succeeds,
reparent the split BTF to the base BTF.

Relocation is done by first verifying that distilled base BTF
only consists of named INT, FLOAT, ENUM, FWD, STRUCT and
UNION kinds; then we sort these to speed lookups.  Once sorted,
the base BTF is iterated, and for each relevant kind we check
for an equivalent in distilled base BTF.  When found, the
mapping from distilled -> base BTF id and string offset is recorded.
In establishing mappings, we need to ensure we check STRUCT/UNION
size when the STRUCT/UNION is embedded in a split BTF STRUCT/UNION,
and when duplicate names exist for the same STRUCT/UNION.  Otherwise
size is ignored in matching STRUCT/UNIONs.

Once all mappings are established, we can update type ids
and string offsets in split BTF and reparent it to the new base.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Ensure relocated BTF looks as expected; in this case identical to
original split BTF, with a few duplicate anonymous types added to
split BTF by the relocation process.  Also add relocation tests
for edge cases like missing type in base BTF and multiple types
of the same name.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Update btf_parse_elf() to check if .BTF.base section is present.
The logic is as follows:

  if .BTF.base section exists:
     distilled_base := btf_new(.BTF.base)
  if distilled_base:
     btf := btf_new(.BTF, .base_btf=distilled_base)
     if base_btf:
        btf_relocate(btf, base_btf)
  else:
     btf := btf_new(.BTF)
  return btf

In other words:
- if .BTF.base section exists, load BTF from it and use it as a base
  for .BTF load;
- if base_btf is specified and .BTF.base section exist, relocate newly
  loaded .BTF against base_btf.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Now that btf_parse_elf() handles .BTF.base section presence,
we need to ensure that resolve_btfids uses .BTF.base when present
rather than the vmlinux base BTF passed in via the -B option.
Detect .BTF.base section presence and unset the base BTF path
to ensure that BTF ELF parsing will do the right thing.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Reviewed-by: Eduard Zingerman <eddyz87@gmail.com>
...as this will allow split BTF modules with a base BTF
representation (rather than the full vmlinux BTF at time of
BTF encoding) to resolve their references to kernel types in a
way that is more resilient to small changes in kernel types.

This will allow modules that are not built every time the kernel
is to provide more resilient BTF, rather than have it invalidated
every time BTF ids for core kernel types change.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: dedf56d
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=861557
version: 6

Share relocation implementation with the kernel.  As part of this,
we also need the type/string iteration functions so add them to a
btf_iter.c file that also gets shared with the kernel. Relocation
code in kernel and userspace is identical save for the impementation
of the reparenting of split BTF to the relocated base BTF and
retrieval of BTF header from "struct btf"; these small functions
need separate user-space and kernel implementations.

One other wrinkle on the kernel side is we have to map .BTF.ids in
modules as they were generated with the type ids used at BTF encoding
time. btf_relocate() optionally returns an array mapping from old BTF
ids to relocated ids, so we use that to fix up these references where
needed for kfuncs.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Support creation of module BTF along with distilled base BTF;
the latter is stored in a .BTF.base ELF section and supplements
split BTF references to base BTF with information about base types,
allowing for later relocation of split BTF with a (possibly
changed) base.  resolve_btfids detects the presence of a .BTF.base
section and will use it instead of the base BTF it is passed in
BTF id resolution.

Modules will be built with a distilled .BTF.base section for external
module build, i.e.

make -C. -M=path2/module

...while in-tree module build as part of a normal kernel build will
not generate distilled base BTF; this is because in-tree modules
change with the kernel and do not require BTF relocation for the
running vmlinux.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
@kernel-patches-daemon-bpf
Copy link
Author

Upstream branch: f6afdaf
series: https://patchwork.kernel.org/project/netdevbpf/list/?series=861557
version: 6

Pull request is NOT updated. Failed to apply https://patchwork.kernel.org/project/netdevbpf/list/?series=861557
error message:

Cmd('git') failed due to: exit code(128)
  cmdline: git am --3way
  stdout: 'Applying: libbpf: add btf__distill_base() creating split BTF with distilled base BTF
Using index info to reconstruct a base tree...
M	tools/lib/bpf/btf.c
M	tools/lib/bpf/btf.h
M	tools/lib/bpf/libbpf.map
Falling back to patching base and 3-way merge...
Auto-merging tools/lib/bpf/libbpf.map
CONFLICT (content): Merge conflict in tools/lib/bpf/libbpf.map
Auto-merging tools/lib/bpf/btf.h
Auto-merging tools/lib/bpf/btf.c
CONFLICT (content): Merge conflict in tools/lib/bpf/btf.c
Patch failed at 0001 libbpf: add btf__distill_base() creating split BTF with distilled base BTF
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".'
  stderr: 'error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch'

conflict:

diff --cc tools/lib/bpf/btf.c
index ef1b2f573c1b,407ed92b4134..000000000000
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@@ -5635,24 -5583,3 +5635,27 @@@ done
  
  	return 0;
  }
++<<<<<<< HEAD
 +
 +const struct btf_header *btf_header(const struct btf *btf)
 +{
 +	return btf->hdr;
 +}
 +
 +void btf_set_base_btf(struct btf *btf, const struct btf *base_btf)
 +{
 +	btf->base_btf = (struct btf *)base_btf;
 +	btf->start_id = btf__type_cnt(base_btf);
 +	btf->start_str_off = base_btf->hdr->str_len;
 +}
 +
 +int btf__relocate(struct btf *btf, const struct btf *base_btf)
 +{
 +	int err = btf_relocate(btf, base_btf, NULL);
 +
 +	if (!err)
 +		btf->owns_base = false;
 +	return libbpf_err(err);
 +}
++=======
++>>>>>>> libbpf: add btf__distill_base() creating split BTF with distilled base BTF
diff --cc tools/lib/bpf/libbpf.map
index 8f0d9ea3b1b4,175d1536e070..000000000000
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@@ -420,7 -420,6 +420,10 @@@ LIBBPF_1.4.0 
  LIBBPF_1.5.0 {
  	global:
  		btf__distill_base;
++<<<<<<< HEAD
 +		btf__relocate;
++=======
++>>>>>>> libbpf: add btf__distill_base() creating split BTF with distilled base BTF
  		bpf_map__autoattach;
  		bpf_map__set_autoattach;
  		bpf_program__attach_sockmap;

@kernel-patches-daemon-bpf
Copy link
Author

At least one diff in series https://patchwork.kernel.org/project/netdevbpf/list/?series=861557 irrelevant now. Closing PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants