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

link: document AttachCgroup and flags #980

Merged
merged 2 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 34 additions & 19 deletions link/cgroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ import (

type cgroupAttachFlags uint32

// cgroup attach flags
const (
// Allow programs attached to sub-cgroups to override the verdict of this
// program.
flagAllowOverride cgroupAttachFlags = 1 << iota
// Allow attaching multiple programs to the cgroup. Only works if the cgroup
// has zero or more programs attached using the Multi flag. Implies override.
flagAllowMulti
// Set automatically by progAttachCgroup.Update(). Used for updating a
// specific given program attached in multi-mode.
flagReplace
)

Expand All @@ -27,36 +32,39 @@ type CgroupOptions struct {
}

// AttachCgroup links a BPF program to a cgroup.
func AttachCgroup(opts CgroupOptions) (Link, error) {
//
// If the running kernel doesn't support bpf_link, attempts to emulate its
// semantics using the legacy PROG_ATTACH mechanism. If bpf_link is not
// available, the returned [Link] will not support pinning to bpffs.
//
// If you need more control over attachment flags or the attachment mechanism
// used, look at [RawAttachProgram] and [AttachRawLink] instead.
func AttachCgroup(opts CgroupOptions) (cg Link, err error) {
cgroup, err := os.Open(opts.Path)
if err != nil {
return nil, fmt.Errorf("can't open cgroup: %s", err)
}

clone, err := opts.Program.Clone()
if err != nil {
defer func() {
if _, ok := cg.(*progAttachCgroup); ok {
// Skip closing the cgroup handle if we return a valid progAttachCgroup,
// where the handle is retained to implement Update().
return
}
cgroup.Close()
return nil, err
}
}()

var cg Link
cg, err = newLinkCgroup(cgroup, opts.Attach, clone)
cg, err = newLinkCgroup(cgroup, opts.Attach, opts.Program)
if err == nil {
cgroup.Close()
clone.Close()
return cg, nil
}

// cgroup and clone are retained by progAttachCgroup.
if errors.Is(err, ErrNotSupported) {
cg, err = newProgAttachCgroup(cgroup, opts.Attach, clone, flagAllowMulti)
cg, err = newProgAttachCgroup(cgroup, opts.Attach, opts.Program, flagAllowMulti)
}
if errors.Is(err, ErrNotSupported) {
cg, err = newProgAttachCgroup(cgroup, opts.Attach, clone, flagAllowOverride)
cg, err = newProgAttachCgroup(cgroup, opts.Attach, opts.Program, flagAllowOverride)
}
if err != nil {
cgroup.Close()
clone.Close()
return nil, err
}

Expand All @@ -83,17 +91,24 @@ func newProgAttachCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Pro
}
}

err := RawAttachProgram(RawAttachProgramOptions{
// Use a program handle that cannot be closed by the caller.
clone, err := prog.Clone()
if err != nil {
return nil, err
}

err = RawAttachProgram(RawAttachProgramOptions{
Target: int(cgroup.Fd()),
Program: prog,
Program: clone,
Flags: uint32(flags),
Attach: attach,
})
if err != nil {
clone.Close()
return nil, fmt.Errorf("cgroup: %w", err)
}

return &progAttachCgroup{cgroup, prog, attach, flags}, nil
return &progAttachCgroup{cgroup, clone, attach, flags}, nil
}

func (cg *progAttachCgroup) Close() error {
Expand Down
6 changes: 3 additions & 3 deletions link/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ type QueryOptions struct {

// QueryPrograms retrieves ProgramIDs associated with the AttachType.
//
// It only returns IDs of programs that were attached using PROG_ATTACH and not bpf_link.
// Returns (nil, nil) if there are no programs attached to the queried kernel resource.
// Calling QueryPrograms on a kernel missing PROG_QUERY will result in ErrNotSupported.
// Returns (nil, nil) if there are no programs attached to the queried kernel
// resource. Calling QueryPrograms on a kernel missing PROG_QUERY will result in
// ErrNotSupported.
func QueryPrograms(opts QueryOptions) ([]ebpf.ProgramID, error) {
if haveProgQuery() != nil {
return nil, fmt.Errorf("can't query program IDs: %w", ErrNotSupported)
Expand Down
2 changes: 1 addition & 1 deletion link/syscalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", "4.10", func() e
return nil
})

var haveProgAttachReplace = internal.NewFeatureTest("BPF_PROG_ATTACH atomic replacement", "5.5", func() error {
var haveProgAttachReplace = internal.NewFeatureTest("BPF_PROG_ATTACH atomic replacement of MULTI progs", "5.5", func() error {
if err := haveProgAttach(); err != nil {
return err
}
Expand Down