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

Collection: add Variables field to interact with global variables #1572

Merged
merged 6 commits into from
Nov 7, 2024

Conversation

ti-mo
Copy link
Collaborator

@ti-mo ti-mo commented Oct 1, 2024

See individual commits for more detailed information.

  • Extend Global Variables documentation

@ti-mo ti-mo force-pushed the tb/ebpf-variables branch 3 times, most recently from 122aa9f to 80e83a4 Compare October 2, 2024 10:14
@ti-mo ti-mo force-pushed the tb/ebpf-variables branch 4 times, most recently from d6f5e4b to b9faaef Compare October 3, 2024 16:16
memory.go Outdated Show resolved Hide resolved
memory.go Outdated Show resolved Hide resolved
memory.go Show resolved Hide resolved
@ti-mo ti-mo force-pushed the tb/ebpf-variables branch 2 times, most recently from 4afef00 to e3fa12b Compare October 9, 2024 15:57
@ti-mo
Copy link
Collaborator Author

ti-mo commented Oct 24, 2024

Gave this a rebase. I made sure we allocate an extra page to guarantee we find a usable page boundary and added some memory coherence notes on Memory. Documentation to be done after autumn break.

@ti-mo ti-mo marked this pull request as ready for review October 24, 2024 13:34
@ti-mo ti-mo requested a review from a team as a code owner October 24, 2024 13:34
@lmb
Copy link
Collaborator

lmb commented Oct 24, 2024

I'll make some time next week to review this.

@ti-mo ti-mo force-pushed the tb/ebpf-variables branch 2 times, most recently from f55c4e4 to f235059 Compare October 24, 2024 15:46
@ti-mo
Copy link
Collaborator Author

ti-mo commented Oct 24, 2024

I've added a small docs section on Variable and Collection.Variables, should be enough for now. More will be added with the MemoryPointer and VariablePointer follow-up PR.

lmb
lmb previously requested changes Nov 2, 2024
Copy link
Collaborator

@lmb lmb left a comment

Choose a reason for hiding this comment

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

I really like how modifying the variable via the getter and setter work, I feel like it integrates with the rest of the API very well.

As you can imagine I'm a little bit hesitant about Memory. From reading the discussion on Slack it seems like the core idea behind it is to (at some later point) facilitate atomic access for things like uint64 and to maybe make arena memory usable like Go memory.

The latter is an intriguing idea but I worry that it'll cause us to paint ourselves into a corner. Once we add an API which "transmutes" the off-heap BPF arena memory into a Go pointer "tracked" by the GC we lose all ability to fix things later on. There is pretty much just a single way of implementing this. And while the implementation works right now (on the platforms we test) there is no guarantee that it will continue to do so. Worse, if the package is considered sufficiently important it might even prevent or constrain future improvements on the Go runtime side. We've seen this happen with the recent go:linkname debacle and I think we need to take this into account. Because it's not at all clear what sharing an arena is useful for I think we shouldn't shape our implementation based on this.

This leaves the atomic access to variables. I can't find the old branch, but I think in a previous iteration there were a bunch of wrapper types like ebpf.Uint64 etc. that abstracted the atomic access away. That added a lot of boilerplate and probably also makes code generation via bpf2go or similar more complicated. Now the plan is (if I understand correctly) to just directly access typed memory via the atomic package. I think there might be a third way, by mediating atomic access via Get and Set.

func (v *Variable) Set(value any) error {
	switch value := value.(type) {
	case uint64:
		if v.size != unsafe.Sizeof(value) && v.offset % unsafe.Alignof(value) {
			return errors.New("bad!")
		}
		atomic.StoreUint64(v.addr(), value)
		return nil

	// ...
	}
}

This only covers the most basic atomic accesses, but that is probably fine for 90% of the cases? If we ever need more access we could add a function like the following:

// VariableMemory allows accessing a variable as a pointer.
//
// It is not valid to access ptr outside of the closure it is passed into.
//
// Returns an error if T is not compatible with the variable.
func VariableMemory[T any](v *Variable, func(ptr *T) error) error

Behind the scenes each Variable would refer to a Memory (though I'd probably unexport that for now) which is used to unmap the memory with a finalizer.

internal/unix/types_linux_noarm.go Outdated Show resolved Hide resolved
collection.go Outdated Show resolved Hide resolved
map.go Outdated Show resolved Hide resolved
variable.go Outdated Show resolved Hide resolved
variable.go Show resolved Hide resolved
memory.go Outdated Show resolved Hide resolved
memory.go Outdated Show resolved Hide resolved
memory.go Outdated Show resolved Hide resolved
memory.go Outdated Show resolved Hide resolved
memory.go Outdated Show resolved Hide resolved
This is getting a bit unwieldy with Variable tests being added
here in a follow-up commit. Split them off into variables.c.

Signed-off-by: Timo Beckers <[email protected]>
Having the enclosed btf.Var containing the variable's offset is an
implementation detail. Return the inner type instead.

Signed-off-by: Timo Beckers <[email protected]>
@ti-mo ti-mo force-pushed the tb/ebpf-variables branch 2 times, most recently from ba2282a to 1280990 Compare November 6, 2024 10:47
@ti-mo ti-mo requested a review from lmb November 6, 2024 10:47
@mejedi
Copy link
Contributor

mejedi commented Nov 6, 2024

@lmb

As you can imagine I'm a little bit hesitant about Memory. From reading the discussion on Slack it seems like the core idea behind it is to (at some later point) facilitate atomic access for things like uint64 and to maybe make arena memory usable like Go memory.

For me, the most appealing aspect of it was compound types, not the arena. If a variable is a structure with fields, how would one access those individually from golang? I tend to agree with you that the hack is risky; I'll try to write a proposal and if it goes well, we might get gcmmap in golang in a year or two. Based on what I learned about golang internals, the implementation should be rather straight-forward.

I'd like to have something less arcane than the proposed VariableMemory though:

func VariableMemory[T any](v *Variable, func(ptr *T) error) error

A callback can leak the pointer, hence this design doesn't buy us much in terms of safety. Would it be possible to have an honest .UnsafePointer() on a variable?

Signed-off-by: Timo Beckers <[email protected]>
Add a little blurb to distinguish VariableSpec and Variable and clarify the
difference between accessing globals before and after loading.

Signed-off-by: Timo Beckers <[email protected]>
@ti-mo
Copy link
Collaborator Author

ti-mo commented Nov 7, 2024

I've addressed all feedback, I think I'll merge this so we can move on. It feels like we need a bit more support from the runtime to make native variable pointers a reality, but in the meantime, the branch with Variable/MemoryPointer and heap mmapping lives here: https://github.com/ti-mo/ebpf/commits/tb/atomic-memory.

I've experimented with the closure suggestion and it's indeed incredibly clunky, though it does move us closer to our goal. It does guarantee the Variable/Memory lifetime for the duration of the variable access, and it's not terribly prone to misuse, even though it can be. It's not a solution I'm comfortable pushing towards our users, though. For now, I think the current proposal is shippable and adds good value, so let's not hold it up any further.

I've created a Go proposal (golang/go#70224) and it's received at least some form of positive traction. Let's see how it plays out.

@ti-mo ti-mo dismissed lmb’s stale review November 7, 2024 13:51

Feedback addressed

@ti-mo ti-mo merged commit 9894d25 into cilium:main Nov 7, 2024
16 of 17 checks passed
@ti-mo ti-mo deleted the tb/ebpf-variables branch November 7, 2024 13:52
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.

3 participants