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

btf: work around missing ENUM64 support #1132

Merged
merged 3 commits into from
Sep 19, 2023
Merged

Conversation

lmb
Copy link
Collaborator

@lmb lmb commented Sep 13, 2023

btf: move feature tests to separate file

No other changes intended.

Signed-off-by: Lorenz Bauer <lmb@isovalent.com>

btf: add feature test for BTF_KIND_ENUM64

Signed-off-by: Lorenz Bauer <lmb@isovalent.com>

btf: work around missing ENUM64 support on older kernels

Replace an ENUM64 with a 64-bit integer on kernels which don't support the
former. This behaviour is similar to libbpf, which replaces the ENUM64 with
a union instead.

Remove the old heuristic which encoded a 64-bit enum as a 32-bit enum if
none of the values exceeded math.MaxUint32. The heuristic has no tests and
doesn't take the signedness of the enum into account.

Signed-off-by: Lorenz Bauer <lmb@isovalent.com>

Fixes #1116

@lmb
Copy link
Collaborator Author

lmb commented Sep 13, 2023

libbpf implementation was added in https://lwn.net/ml/bpf/20220603015937.1190992-1-yhs@fb.com/

@lmb lmb force-pushed the enum64-workaround branch 3 times, most recently from 81fae4b to d02ac56 Compare September 13, 2023 14:24
@lmb lmb marked this pull request as ready for review September 13, 2023 14:45
@lmb lmb requested review from ti-mo and rgo3 September 13, 2023 14:45
btf/marshal.go Outdated Show resolved Hide resolved
@lmb
Copy link
Collaborator Author

lmb commented Sep 14, 2023

Now uses a union instead of the int. Please take another look.

@@ -464,6 +483,41 @@ func (e *encoder) deflateEnumValues(values []EnumValue) ([]btfEnum, error) {
return bes, nil
}

func (e *encoder) deflateEnum64(raw *rawType, enum *Enum) (err error) {
if e.ReplaceEnum64 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a quick explanation with some context here. (e.g. why a union and not simply an int like we discussed offline)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point, but I'll add it to the commit message instead. I think the comment would be too large.

btf/marshal.go Outdated
return nil, fmt.Errorf("value of enum %q exceeds 32 bits", value.Name)
if enum.Signed {
signedValue := int64(value.Value)
if signedValue != int64(int32(uint32(value.Value))) {
Copy link
Collaborator

@ti-mo ti-mo Sep 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too clever to be uncommented. Why compare value.Value against its sign-extended self? Wouldn't truncating it to 32 bits put it within acceptable range anyway? (I assume that's part of the trick) FYI there's now math.MaxInt32 as well, maybe just check if value.Value falls within MaxInt32 and MaxUint32 instead of special-casing signed/unsigned?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, comparing against the constants is much easier to understand.

ti-mo
ti-mo previously requested changes Sep 15, 2023
Copy link
Collaborator

@ti-mo ti-mo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Let's make the bounds check a little clearer if possible. 🙏

No other changes intended.

Signed-off-by: Lorenz Bauer <lmb@isovalent.com>
Signed-off-by: Lorenz Bauer <lmb@isovalent.com>
Replace an ENUM64 with a 64-bit integer on kernels which don't
support the former. Match libbpf behaviour by replacing the enum with
a union. I initially considered replacing it with an int instead,
but this can create interoperability problems with libbpf.

For example, consider a BPF program loaded by libbpf which contains
a function signature that takes an enum64 as an argument. libbpf will
replace the enum with a union. Instead of func(enum) we have func(union).
This becomes important when the kernel compares type signatures as
part of UAPI, like when attaching a BPF program to the function entry
of the func(enum) (the mind boggles). If we replaced func(enum) with
func(int) the in-kernel comparison would fail. Hence we match what
libbpf does.

Remove the old heuristic which encoded a 64-bit enum as a 32-bit enum
if none of the values exceeded math.MaxUint32. The heuristic has no
tests and doesn't take the signedness of the enum into account.

Signed-off-by: Lorenz Bauer <lmb@isovalent.com>
@lmb lmb dismissed ti-mo’s stale review September 19, 2023 06:22

Review addressed

@lmb lmb merged commit 8fada76 into cilium:main Sep 19, 2023
10 checks passed
@lmb lmb deleted the enum64-workaround branch September 19, 2023 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

btf: provide work around for missing BTF_KIND_ENUM64 support
3 participants