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

CollectionSpec: add new Variables field to interact with constants and global variables #1564

Merged
merged 5 commits into from
Sep 24, 2024

Conversation

ti-mo
Copy link
Collaborator

@ti-mo ti-mo commented Sep 12, 2024

See individual commits for details and design considerations.

See https://deploy-preview-1564--ebpf-go.netlify.app/concepts/global-variables for documentation and a quick overview of the API.

Minor breaking change: RewriteConstants and the new CollectionSpec.Variables no longer expose global variables with the static keyword as they cannot be distinguished from function-scoped, local variables. This conforms to libbpf behaviour that doesn't expose static vars in bpf-skeleton.

…ndler

Signed-off-by: Timo Beckers <timo@isovalent.com>
@ti-mo ti-mo requested a review from a team as a code owner September 12, 2024 14:13
@ti-mo ti-mo requested review from dylandreimerink, mejedi, lmb and florianl and removed request for a team September 12, 2024 14:14
Copy link
Contributor

@mejedi mejedi left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@dylandreimerink dylandreimerink left a comment

Choose a reason for hiding this comment

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

This is great! Can't find anything to complain about

This commit adds a new field to CollectionSpec: Variables. Along with it,
a new type is introduced, the VariableSpec. It acts as a view into a data
section representing global variables and constants. They can be get and
set freely before loading the CollectionSpec into the kernel, after which
they will be converted into a new type, a Variable, which will be added
in a follow-up commit.

Like ProgramSpec and MapSpec, a VariableSpec can be assigned to a struct
using CollectionSpec.Assign. Should the programmer wish to hide certain
variables from being exposed in the CollectionSpec, they can be marked
using the 'hidden' C visibility attribute.

With this commit, all data sections are now included in the CollectionSpec
tests, while they were excluded before. This ensures a consistent experience
across LLVM versions.

Much of the code was borrowed from RewriteConstants, which will be turned
into a wrapper around CollectionSpec.Variables in a follow-up commit.

Signed-off-by: Timo Beckers <timo@isovalent.com>
@ti-mo ti-mo added the breaking-change Changes exported API label Sep 24, 2024
@ti-mo ti-mo force-pushed the tb/collectionspec-variables branch from 5e7deec to f692e23 Compare September 24, 2024 11:02
@github-actions github-actions bot removed the breaking-change Changes exported API label Sep 24, 2024
…iables

This constitutes a small breaking behavioural change: RewriteConstants
no longer sees 'global' variables with the static qualifier. Drop the
static qualifier if you want to manage variables from user space.

Signed-off-by: Timo Beckers <timo@isovalent.com>
Inspired by the badges in the upstream mkdocs-material project,
add a macro to display a version number with a small tooltip describing
why the functionality needs a particular version.

Signed-off-by: Timo Beckers <timo@isovalent.com>
Signed-off-by: Timo Beckers <timo@isovalent.com>
@ti-mo ti-mo force-pushed the tb/collectionspec-variables branch from f692e23 to 3085570 Compare September 24, 2024 11:04
@ti-mo ti-mo merged commit d3c55aa into cilium:main Sep 24, 2024
17 checks passed
@ti-mo ti-mo deleted the tb/collectionspec-variables branch September 24, 2024 12:20
@alban
Copy link
Contributor

alban commented Oct 21, 2024

FYI in Inspektor Gadget, we have unit tests with ebpf.CollectionSpec defined manually (not read from an ELF file):
https://github.com/inspektor-gadget/inspektor-gadget/blob/0cce8189cbaebdfc9c9a49ccc1bb471369e4154e/pkg/kallsyms/kallsyms_test.go#L87-L122

Then we call spec.RewriteConstants to check if our kallsyms package works correctly. (our kallsyms package offers a different feature set than cilium/ebpf one, so we can't use remove it)

When I update to the new cilium/ebpf with this PR, the tests fail because spec.RewriteConstants does not find the Variables section, even if the spec has the correct ".rodata" map:

        	Error Trace:	/home/runner/work/inspektor-gadget/inspektor-gadget/pkg/kallsyms/kallsyms_test.go:162
        	Error:      	Expected nil, but got: &fmt.wrapError{msg:"rewriting constants: rewrite constants: some constants are missing from .rodata: socket_file_ops_addr, bpf_prog_fops_addr", err:(*fmt.wrapError)(0xc0000320e0)}
        	Test:       	TestSpecRewriteConstants
        	Messages:   	specUpdateAddresses failed: rewriting constants: rewrite constants: some constants are missing from .rodata: socket_file_ops_addr, bpf_prog_fops_addr

In this PR, it is not possible to instantiate a ebpf.CollectionSpec with variables because the fields of spec.Variables[*] are not exported. Could those fields be exported? Or any idea how to write the unit tests differently?

Found while working on inspektor-gadget/inspektor-gadget#3595

cc @ti-mo @burak-ok

@lmb
Copy link
Collaborator

lmb commented Oct 21, 2024

I haven't looked at the PR in detail, but so far all the other *Specs have had only public fields for this reason (with some temporary exceptions which we managed to fix over time). I think it would be desirable to be able to create VariableSpec just like ProgramSpec, etc.

@ti-mo
Copy link
Collaborator Author

ti-mo commented Oct 25, 2024

@alban Thanks for the feedback! Note that the next release will deprecate RewriteConstants, it's now just a wrapper around spec.Variables as you've noticed. The .rodata mention in the error string is a red herring, it doesn't actually check the .rodata map anymore

Note that we don't really encourage manually creating CollectionSpecs. We do it in a few places in tests for testing specific behaviours, but nothing major.

As for your problem, I assume you're testing for ErrMissingConstant (iirc). Going forward, you could populate CollectionSpec.Variables with empty values and let your kallsyms parser just do a membership check on the map.

Alternatively, I wouldn't mind adding a NewVariableSpec() constructor, it could be useful beyond tests. Exporting fields will make for ugly API as VariableSpec are primarily meant as accessors.

@lmb
Copy link
Collaborator

lmb commented Nov 2, 2024

Alternatively, I wouldn't mind adding a NewVariableSpec() constructor, it could be useful beyond tests. Exporting fields will make for ugly API as VariableSpec are primarily meant as accessors.

What if we turn things around, and instead of variable spec being accessors for special maps we synthesise the necessary maps by assembling the VariableSpec into a map?

P.S. The implication being that instructions would start referring to VariableSpec instead of using a stringly reference + offset encoded in the instruction.

@mejedi
Copy link
Contributor

mejedi commented Nov 2, 2024

What if we turn things around, and instead of variable spec being accessors for special maps we synthesise the necessary maps by assembling the VariableSpec into a map?

There’re no variableSpecs created for hidden variables (intentionally), hence the process is lossy. It is not just BTF, potentially even the size can change.

Today, it is possible to create custom data sections and manipulate the mapSpec for tricks like resizable buffers with fast access or fine-grained protection (BPF_F_MAP_RDONLY_PROG, etc.) It depends on having a mapSpec accessible.

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.

5 participants