diff --git a/collection.go b/collection.go index aedce656c..7ba15e128 100644 --- a/collection.go +++ b/collection.go @@ -286,7 +286,11 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Co } } - for progName := range spec.Programs { + for progName, prog := range spec.Programs { + if prog.Type == UnspecifiedProgram { + continue + } + if _, err := loader.loadProgram(progName); err != nil { return nil, err } @@ -424,6 +428,12 @@ func (cl *collectionLoader) loadProgram(progName string) (*Program, error) { return nil, fmt.Errorf("unknown program %s", progName) } + // Bail out early if we know the kernel is going to reject the program. + // This skips loading map dependencies, saving some cleanup work later. + if progSpec.Type == UnspecifiedProgram { + return nil, fmt.Errorf("cannot load program %s: program type is unspecified", progName) + } + progSpec = progSpec.Copy() // Rewrite any reference to a valid map in the program's instructions, diff --git a/elf_reader.go b/elf_reader.go index 4c350443d..f1111edab 100644 --- a/elf_reader.go +++ b/elf_reader.go @@ -297,6 +297,7 @@ func (ec *elfCode) loadProgramSections() (map[string]*ProgramSpec, error) { Flags: progFlags, AttachType: attachType, AttachTo: attachTo, + SectionName: sec.Name, License: ec.license, KernelVersion: ec.version, Instructions: insns, @@ -323,9 +324,11 @@ func (ec *elfCode) loadProgramSections() (map[string]*ProgramSpec, error) { return nil, fmt.Errorf("populating references: %w", err) } - // Don't emit programs of unknown type to preserve backwards compatibility. + // Hide programs (e.g. library functions) that were not explicitly emitted + // to an ELF section. These could be exposed in a separate CollectionSpec + // field later to allow them to be modified. for n, p := range progs { - if p.Type == UnspecifiedProgram { + if p.SectionName == ".text" { delete(progs, n) } } diff --git a/elf_reader_test.go b/elf_reader_test.go index 8c1fe51ef..26dac77de 100644 --- a/elf_reader_test.go +++ b/elf_reader_test.go @@ -96,24 +96,40 @@ func TestLoadCollectionSpec(t *testing.T) { }, Programs: map[string]*ProgramSpec{ "xdp_prog": { - Name: "xdp_prog", - Type: XDP, - License: "MIT", + Name: "xdp_prog", + Type: XDP, + SectionName: "xdp", + License: "MIT", }, "no_relocation": { - Name: "no_relocation", - Type: SocketFilter, - License: "MIT", + Name: "no_relocation", + Type: SocketFilter, + SectionName: "socket", + License: "MIT", }, "asm_relocation": { - Name: "asm_relocation", - Type: SocketFilter, - License: "MIT", + Name: "asm_relocation", + Type: SocketFilter, + SectionName: "socket/2", + License: "MIT", }, "data_sections": { - Name: "data_sections", - Type: SocketFilter, - License: "MIT", + Name: "data_sections", + Type: SocketFilter, + SectionName: "socket/3", + License: "MIT", + }, + "global_fn3": { + Name: "global_fn3", + Type: UnspecifiedProgram, + SectionName: "other", + License: "MIT", + }, + "static_fn": { + Name: "static_fn", + Type: UnspecifiedProgram, + SectionName: "static", + License: "MIT", }, }, } diff --git a/prog.go b/prog.go index 84c3b2a2c..6da311437 100644 --- a/prog.go +++ b/prog.go @@ -62,11 +62,17 @@ type ProgramSpec struct { // Type determines at which hook in the kernel a program will run. Type ProgramType AttachType AttachType + // Name of a kernel data structure or function to attach to. Its // interpretation depends on Type and AttachType. AttachTo string + // The program to attach to. Must be provided manually. AttachTarget *Program + + // The name of the ELF section this program orininated from. + SectionName string + Instructions asm.Instructions // Flags is passed to the kernel and specifies additional program