Skip to content

Conversation

@ianchen0119
Copy link
Contributor

All of the variables located in the rodata/bss section will be mapped into an eBPF map during the eBPF program's runtime.
And there are some known limitations:

  1. The rodata section can only be overwritten before the eBPF program is attached.
  2. The BSS section can be modified via MAP Update. But the data synchronization can't be guaranteed.

It was a significant challenge when I attempted to implement the user-space scheduler in Go.
My solution is to use the cgo to call eBPF skeleton APIs, so I need an additional wrapper to replace the existing eBPF object before the program attaches.

=== example ===

// ...

func LoadSkel() unsafe.Pointer {
	return C.open_skel()
}

func LoadSched(objPath string) *Sched {
	obj := LoadSkel()
	bpfModule, err := bpf.NewModuleFromFileArgs(bpf.NewModuleArgs{
		BPFObjPath:     "",
		KernelLogLevel: 0,
	})
	if err != nil {
		panic(err)
	}
	if err := bpfModule.BPFReplaceExistedObject(obj); err != nil {
		panic(err)
	}

	s := &Sched{
		mod: bpfModule,
	}

	return s
}

func (s *Sched) SetBuiltinIdle(enabled bool) {
	C.set_builtin_idle(C.bool(enabled))
}

func (s *Sched) Attach() error {
	_, err := s.structOps.AttachStructOps()
	return err
}
void set_builtin_idle(bool enabled) {
    global_obj->rodata->builtin_idle = enabled;
}

Therefore, I can call SetBuiltinIdle() before Attach() to modify the target variable builtin_idle in the rodata section.

Copilot AI review requested due to automatic review settings September 1, 2025 12:39
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds a new method BPFReplaceExistedObject to the Module struct that allows replacing an existing BPF object with one passed from external code (e.g., CGO). This enables modifying rodata section variables before program attachment, which is particularly useful for user-space schedulers that need to configure BPF programs through C skeleton APIs.

  • Adds BPFReplaceExistedObject method to replace the internal BPF object pointer
  • Enables modification of rodata section variables before program attachment
  • Supports integration with CGO-based BPF skeleton workflows

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

module.go Outdated
return nil
}

func (m *Module) BPFReplaceExistedObject(obj unsafe.Pointer) error {
Copy link

Copilot AI Sep 1, 2025

Choose a reason for hiding this comment

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

The method name contains a spelling error. 'ExistedObject' should be 'ExistingObject'. The correct name should be BPFReplaceExistingObject.

Suggested change
func (m *Module) BPFReplaceExistedObject(obj unsafe.Pointer) error {
func (m *Module) BPFReplaceExistingObject(obj unsafe.Pointer) error {

Copilot uses AI. Check for mistakes.
module.go Outdated
return nil
}

func (m *Module) BPFReplaceExistedObject(obj unsafe.Pointer) error {
Copy link

Copilot AI Sep 1, 2025

Choose a reason for hiding this comment

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

The method lacks input validation. It should check if the obj parameter is nil before casting and assignment to prevent potential runtime panics.

Suggested change
func (m *Module) BPFReplaceExistedObject(obj unsafe.Pointer) error {
func (m *Module) BPFReplaceExistedObject(obj unsafe.Pointer) error {
if obj == nil {
return errors.New("obj parameter is nil")
}

Copilot uses AI. Check for mistakes.
@ianchen0119
Copy link
Contributor Author

Hi @geyslan

The Gthulhu is now able to be used in 5G Data Plane optimization! For more details, please visit https://free5gc.org/blog/20250726/index.en.
Additionally, if you can help promote the Gthulhu, it would be great! We're currently aiming for CNCF Landscape recognition — the maintainers are happy to accept the project, but it needs at least 300 ⭐

Thanks a lot!

@geyslan
Copy link
Member

geyslan commented Sep 1, 2025

Hi @ianchen0119 thanks again for contributing to libbpfgo.

  1. The rodata section can only be overwritten before the eBPF program is attached.

Wouldn't InitGlobalVariable() be a solution for this case?

void set_builtin_idle(bool enabled) {
    global_obj->rodata->builtin_idle = enabled;
}

Do you have plans of bringing such functionality into the libbpfgo?

@ianchen0119
Copy link
Contributor Author

Hi @ianchen0119 thanks again for contributing to libbpfgo.

  1. The rodata section can only be overwritten before the eBPF program is attached.

Wouldn't InitGlobalVariable() be a solution for this case?

void set_builtin_idle(bool enabled) {
    global_obj->rodata->builtin_idle = enabled;
}

Do you have plans of bringing such functionality into the libbpfgo?

Sorry for the late reply.
I didn't try the InitGlobalVariable in this case, cuz I think the skeleton is more flexible to update the global data for me.
To use the example above, we need to generate the skeleton file based on the compiled eBPF program, then use an additional file to wrap the static library. I have no idea how to make these things generic. Do you have any suggestion on this?

Thank you!

@ianchen0119
Copy link
Contributor Author

Hi @geyslan
I forgot to tag you in previous comment.
Just want to make sure you've received the status update :)

Thank you!

@geyslan
Copy link
Member

geyslan commented Sep 30, 2025

@ianchen0119 no worries. I'll revisit this soon but I think, for now, that perhaps we could provide a NewModuleFromSkel() which could straightforwardly instantiate the module taking care of setting *C.struct_bpf_object. Please be my guest for testing it.

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.

2 participants