gtsocial-umbx

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

link.go (7231B)


      1 package link
      2 
      3 import (
      4 	"bytes"
      5 	"encoding/binary"
      6 	"fmt"
      7 
      8 	"github.com/cilium/ebpf"
      9 	"github.com/cilium/ebpf/btf"
     10 	"github.com/cilium/ebpf/internal"
     11 	"github.com/cilium/ebpf/internal/sys"
     12 )
     13 
     14 var ErrNotSupported = internal.ErrNotSupported
     15 
     16 // Link represents a Program attached to a BPF hook.
     17 type Link interface {
     18 	// Replace the current program with a new program.
     19 	//
     20 	// Passing a nil program is an error. May return an error wrapping ErrNotSupported.
     21 	Update(*ebpf.Program) error
     22 
     23 	// Persist a link by pinning it into a bpffs.
     24 	//
     25 	// May return an error wrapping ErrNotSupported.
     26 	Pin(string) error
     27 
     28 	// Undo a previous call to Pin.
     29 	//
     30 	// May return an error wrapping ErrNotSupported.
     31 	Unpin() error
     32 
     33 	// Close frees resources.
     34 	//
     35 	// The link will be broken unless it has been successfully pinned.
     36 	// A link may continue past the lifetime of the process if Close is
     37 	// not called.
     38 	Close() error
     39 
     40 	// Info returns metadata on a link.
     41 	//
     42 	// May return an error wrapping ErrNotSupported.
     43 	Info() (*Info, error)
     44 
     45 	// Prevent external users from implementing this interface.
     46 	isLink()
     47 }
     48 
     49 // LoadPinnedLink loads a link that was persisted into a bpffs.
     50 func LoadPinnedLink(fileName string, opts *ebpf.LoadPinOptions) (Link, error) {
     51 	raw, err := loadPinnedRawLink(fileName, opts)
     52 	if err != nil {
     53 		return nil, err
     54 	}
     55 
     56 	return wrapRawLink(raw)
     57 }
     58 
     59 // wrap a RawLink in a more specific type if possible.
     60 //
     61 // The function takes ownership of raw and closes it on error.
     62 func wrapRawLink(raw *RawLink) (Link, error) {
     63 	info, err := raw.Info()
     64 	if err != nil {
     65 		raw.Close()
     66 		return nil, err
     67 	}
     68 
     69 	switch info.Type {
     70 	case RawTracepointType:
     71 		return &rawTracepoint{*raw}, nil
     72 	case TracingType:
     73 		return &tracing{*raw}, nil
     74 	case CgroupType:
     75 		return &linkCgroup{*raw}, nil
     76 	case IterType:
     77 		return &Iter{*raw}, nil
     78 	case NetNsType:
     79 		return &NetNsLink{*raw}, nil
     80 	default:
     81 		return raw, nil
     82 	}
     83 }
     84 
     85 // ID uniquely identifies a BPF link.
     86 type ID = sys.LinkID
     87 
     88 // RawLinkOptions control the creation of a raw link.
     89 type RawLinkOptions struct {
     90 	// File descriptor to attach to. This differs for each attach type.
     91 	Target int
     92 	// Program to attach.
     93 	Program *ebpf.Program
     94 	// Attach must match the attach type of Program.
     95 	Attach ebpf.AttachType
     96 	// BTF is the BTF of the attachment target.
     97 	BTF btf.TypeID
     98 	// Flags control the attach behaviour.
     99 	Flags uint32
    100 }
    101 
    102 // Info contains metadata on a link.
    103 type Info struct {
    104 	Type    Type
    105 	ID      ID
    106 	Program ebpf.ProgramID
    107 	extra   interface{}
    108 }
    109 
    110 type TracingInfo sys.TracingLinkInfo
    111 type CgroupInfo sys.CgroupLinkInfo
    112 type NetNsInfo sys.NetNsLinkInfo
    113 type XDPInfo sys.XDPLinkInfo
    114 
    115 // Tracing returns tracing type-specific link info.
    116 //
    117 // Returns nil if the type-specific link info isn't available.
    118 func (r Info) Tracing() *TracingInfo {
    119 	e, _ := r.extra.(*TracingInfo)
    120 	return e
    121 }
    122 
    123 // Cgroup returns cgroup type-specific link info.
    124 //
    125 // Returns nil if the type-specific link info isn't available.
    126 func (r Info) Cgroup() *CgroupInfo {
    127 	e, _ := r.extra.(*CgroupInfo)
    128 	return e
    129 }
    130 
    131 // NetNs returns netns type-specific link info.
    132 //
    133 // Returns nil if the type-specific link info isn't available.
    134 func (r Info) NetNs() *NetNsInfo {
    135 	e, _ := r.extra.(*NetNsInfo)
    136 	return e
    137 }
    138 
    139 // ExtraNetNs returns XDP type-specific link info.
    140 //
    141 // Returns nil if the type-specific link info isn't available.
    142 func (r Info) XDP() *XDPInfo {
    143 	e, _ := r.extra.(*XDPInfo)
    144 	return e
    145 }
    146 
    147 // RawLink is the low-level API to bpf_link.
    148 //
    149 // You should consider using the higher level interfaces in this
    150 // package instead.
    151 type RawLink struct {
    152 	fd         *sys.FD
    153 	pinnedPath string
    154 }
    155 
    156 // AttachRawLink creates a raw link.
    157 func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
    158 	if err := haveBPFLink(); err != nil {
    159 		return nil, err
    160 	}
    161 
    162 	if opts.Target < 0 {
    163 		return nil, fmt.Errorf("invalid target: %s", sys.ErrClosedFd)
    164 	}
    165 
    166 	progFd := opts.Program.FD()
    167 	if progFd < 0 {
    168 		return nil, fmt.Errorf("invalid program: %s", sys.ErrClosedFd)
    169 	}
    170 
    171 	attr := sys.LinkCreateAttr{
    172 		TargetFd:    uint32(opts.Target),
    173 		ProgFd:      uint32(progFd),
    174 		AttachType:  sys.AttachType(opts.Attach),
    175 		TargetBtfId: uint32(opts.BTF),
    176 		Flags:       opts.Flags,
    177 	}
    178 	fd, err := sys.LinkCreate(&attr)
    179 	if err != nil {
    180 		return nil, fmt.Errorf("can't create link: %s", err)
    181 	}
    182 
    183 	return &RawLink{fd, ""}, nil
    184 }
    185 
    186 func loadPinnedRawLink(fileName string, opts *ebpf.LoadPinOptions) (*RawLink, error) {
    187 	fd, err := sys.ObjGet(&sys.ObjGetAttr{
    188 		Pathname:  sys.NewStringPointer(fileName),
    189 		FileFlags: opts.Marshal(),
    190 	})
    191 	if err != nil {
    192 		return nil, fmt.Errorf("load pinned link: %w", err)
    193 	}
    194 
    195 	return &RawLink{fd, fileName}, nil
    196 }
    197 
    198 func (l *RawLink) isLink() {}
    199 
    200 // FD returns the raw file descriptor.
    201 func (l *RawLink) FD() int {
    202 	return l.fd.Int()
    203 }
    204 
    205 // Close breaks the link.
    206 //
    207 // Use Pin if you want to make the link persistent.
    208 func (l *RawLink) Close() error {
    209 	return l.fd.Close()
    210 }
    211 
    212 // Pin persists a link past the lifetime of the process.
    213 //
    214 // Calling Close on a pinned Link will not break the link
    215 // until the pin is removed.
    216 func (l *RawLink) Pin(fileName string) error {
    217 	if err := internal.Pin(l.pinnedPath, fileName, l.fd); err != nil {
    218 		return err
    219 	}
    220 	l.pinnedPath = fileName
    221 	return nil
    222 }
    223 
    224 // Unpin implements the Link interface.
    225 func (l *RawLink) Unpin() error {
    226 	if err := internal.Unpin(l.pinnedPath); err != nil {
    227 		return err
    228 	}
    229 	l.pinnedPath = ""
    230 	return nil
    231 }
    232 
    233 // Update implements the Link interface.
    234 func (l *RawLink) Update(new *ebpf.Program) error {
    235 	return l.UpdateArgs(RawLinkUpdateOptions{
    236 		New: new,
    237 	})
    238 }
    239 
    240 // RawLinkUpdateOptions control the behaviour of RawLink.UpdateArgs.
    241 type RawLinkUpdateOptions struct {
    242 	New   *ebpf.Program
    243 	Old   *ebpf.Program
    244 	Flags uint32
    245 }
    246 
    247 // UpdateArgs updates a link based on args.
    248 func (l *RawLink) UpdateArgs(opts RawLinkUpdateOptions) error {
    249 	newFd := opts.New.FD()
    250 	if newFd < 0 {
    251 		return fmt.Errorf("invalid program: %s", sys.ErrClosedFd)
    252 	}
    253 
    254 	var oldFd int
    255 	if opts.Old != nil {
    256 		oldFd = opts.Old.FD()
    257 		if oldFd < 0 {
    258 			return fmt.Errorf("invalid replacement program: %s", sys.ErrClosedFd)
    259 		}
    260 	}
    261 
    262 	attr := sys.LinkUpdateAttr{
    263 		LinkFd:    l.fd.Uint(),
    264 		NewProgFd: uint32(newFd),
    265 		OldProgFd: uint32(oldFd),
    266 		Flags:     opts.Flags,
    267 	}
    268 	return sys.LinkUpdate(&attr)
    269 }
    270 
    271 // Info returns metadata about the link.
    272 func (l *RawLink) Info() (*Info, error) {
    273 	var info sys.LinkInfo
    274 
    275 	if err := sys.ObjInfo(l.fd, &info); err != nil {
    276 		return nil, fmt.Errorf("link info: %s", err)
    277 	}
    278 
    279 	var extra interface{}
    280 	switch info.Type {
    281 	case CgroupType:
    282 		extra = &CgroupInfo{}
    283 	case IterType:
    284 		// not supported
    285 	case NetNsType:
    286 		extra = &NetNsInfo{}
    287 	case RawTracepointType:
    288 		// not supported
    289 	case TracingType:
    290 		extra = &TracingInfo{}
    291 	case XDPType:
    292 		extra = &XDPInfo{}
    293 	case PerfEventType:
    294 		// no extra
    295 	default:
    296 		return nil, fmt.Errorf("unknown link info type: %d", info.Type)
    297 	}
    298 
    299 	if info.Type != RawTracepointType && info.Type != IterType && info.Type != PerfEventType {
    300 		buf := bytes.NewReader(info.Extra[:])
    301 		err := binary.Read(buf, internal.NativeEndian, extra)
    302 		if err != nil {
    303 			return nil, fmt.Errorf("can not read extra link info: %w", err)
    304 		}
    305 	}
    306 
    307 	return &Info{
    308 		info.Type,
    309 		info.Id,
    310 		ebpf.ProgramID(info.ProgId),
    311 		extra,
    312 	}, nil
    313 }