gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

cgroup.go (3658B)


      1 package link
      2 
      3 import (
      4 	"errors"
      5 	"fmt"
      6 	"os"
      7 
      8 	"github.com/cilium/ebpf"
      9 )
     10 
     11 type cgroupAttachFlags uint32
     12 
     13 // cgroup attach flags
     14 const (
     15 	flagAllowOverride cgroupAttachFlags = 1 << iota
     16 	flagAllowMulti
     17 	flagReplace
     18 )
     19 
     20 type CgroupOptions struct {
     21 	// Path to a cgroupv2 folder.
     22 	Path string
     23 	// One of the AttachCgroup* constants
     24 	Attach ebpf.AttachType
     25 	// Program must be of type CGroup*, and the attach type must match Attach.
     26 	Program *ebpf.Program
     27 }
     28 
     29 // AttachCgroup links a BPF program to a cgroup.
     30 func AttachCgroup(opts CgroupOptions) (Link, error) {
     31 	cgroup, err := os.Open(opts.Path)
     32 	if err != nil {
     33 		return nil, fmt.Errorf("can't open cgroup: %s", err)
     34 	}
     35 
     36 	clone, err := opts.Program.Clone()
     37 	if err != nil {
     38 		cgroup.Close()
     39 		return nil, err
     40 	}
     41 
     42 	var cg Link
     43 	cg, err = newLinkCgroup(cgroup, opts.Attach, clone)
     44 	if errors.Is(err, ErrNotSupported) {
     45 		cg, err = newProgAttachCgroup(cgroup, opts.Attach, clone, flagAllowMulti)
     46 	}
     47 	if errors.Is(err, ErrNotSupported) {
     48 		cg, err = newProgAttachCgroup(cgroup, opts.Attach, clone, flagAllowOverride)
     49 	}
     50 	if err != nil {
     51 		cgroup.Close()
     52 		clone.Close()
     53 		return nil, err
     54 	}
     55 
     56 	return cg, nil
     57 }
     58 
     59 type progAttachCgroup struct {
     60 	cgroup     *os.File
     61 	current    *ebpf.Program
     62 	attachType ebpf.AttachType
     63 	flags      cgroupAttachFlags
     64 }
     65 
     66 var _ Link = (*progAttachCgroup)(nil)
     67 
     68 func (cg *progAttachCgroup) isLink() {}
     69 
     70 func newProgAttachCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program, flags cgroupAttachFlags) (*progAttachCgroup, error) {
     71 	if flags&flagAllowMulti > 0 {
     72 		if err := haveProgAttachReplace(); err != nil {
     73 			return nil, fmt.Errorf("can't support multiple programs: %w", err)
     74 		}
     75 	}
     76 
     77 	err := RawAttachProgram(RawAttachProgramOptions{
     78 		Target:  int(cgroup.Fd()),
     79 		Program: prog,
     80 		Flags:   uint32(flags),
     81 		Attach:  attach,
     82 	})
     83 	if err != nil {
     84 		return nil, fmt.Errorf("cgroup: %w", err)
     85 	}
     86 
     87 	return &progAttachCgroup{cgroup, prog, attach, flags}, nil
     88 }
     89 
     90 func (cg *progAttachCgroup) Close() error {
     91 	defer cg.cgroup.Close()
     92 	defer cg.current.Close()
     93 
     94 	err := RawDetachProgram(RawDetachProgramOptions{
     95 		Target:  int(cg.cgroup.Fd()),
     96 		Program: cg.current,
     97 		Attach:  cg.attachType,
     98 	})
     99 	if err != nil {
    100 		return fmt.Errorf("close cgroup: %s", err)
    101 	}
    102 	return nil
    103 }
    104 
    105 func (cg *progAttachCgroup) Update(prog *ebpf.Program) error {
    106 	new, err := prog.Clone()
    107 	if err != nil {
    108 		return err
    109 	}
    110 
    111 	args := RawAttachProgramOptions{
    112 		Target:  int(cg.cgroup.Fd()),
    113 		Program: prog,
    114 		Attach:  cg.attachType,
    115 		Flags:   uint32(cg.flags),
    116 	}
    117 
    118 	if cg.flags&flagAllowMulti > 0 {
    119 		// Atomically replacing multiple programs requires at least
    120 		// 5.5 (commit 7dd68b3279f17921 "bpf: Support replacing cgroup-bpf
    121 		// program in MULTI mode")
    122 		args.Flags |= uint32(flagReplace)
    123 		args.Replace = cg.current
    124 	}
    125 
    126 	if err := RawAttachProgram(args); err != nil {
    127 		new.Close()
    128 		return fmt.Errorf("can't update cgroup: %s", err)
    129 	}
    130 
    131 	cg.current.Close()
    132 	cg.current = new
    133 	return nil
    134 }
    135 
    136 func (cg *progAttachCgroup) Pin(string) error {
    137 	return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported)
    138 }
    139 
    140 func (cg *progAttachCgroup) Unpin() error {
    141 	return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported)
    142 }
    143 
    144 func (cg *progAttachCgroup) Info() (*Info, error) {
    145 	return nil, fmt.Errorf("can't get cgroup info: %w", ErrNotSupported)
    146 }
    147 
    148 type linkCgroup struct {
    149 	RawLink
    150 }
    151 
    152 var _ Link = (*linkCgroup)(nil)
    153 
    154 func newLinkCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program) (*linkCgroup, error) {
    155 	link, err := AttachRawLink(RawLinkOptions{
    156 		Target:  int(cgroup.Fd()),
    157 		Program: prog,
    158 		Attach:  attach,
    159 	})
    160 	if err != nil {
    161 		return nil, err
    162 	}
    163 
    164 	return &linkCgroup{*link}, err
    165 }