123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- package link
- import (
- "fmt"
- "unsafe"
- "github.com/cilium/ebpf"
- "github.com/cilium/ebpf/internal"
- )
- var ErrNotSupported = internal.ErrNotSupported
- // Link represents a Program attached to a BPF hook.
- type Link interface {
- // Replace the current program with a new program.
- //
- // Passing a nil program is an error. May return an error wrapping ErrNotSupported.
- Update(*ebpf.Program) error
- // Persist a link by pinning it into a bpffs.
- //
- // May return an error wrapping ErrNotSupported.
- Pin(string) error
- // Close frees resources.
- //
- // The link will be broken unless it has been pinned. A link
- // may continue past the lifetime of the process if Close is
- // not called.
- Close() error
- // Prevent external users from implementing this interface.
- isLink()
- }
- // ID uniquely identifies a BPF link.
- type ID uint32
- // RawLinkOptions control the creation of a raw link.
- type RawLinkOptions struct {
- // File descriptor to attach to. This differs for each attach type.
- Target int
- // Program to attach.
- Program *ebpf.Program
- // Attach must match the attach type of Program.
- Attach ebpf.AttachType
- }
- // RawLinkInfo contains metadata on a link.
- type RawLinkInfo struct {
- Type Type
- ID ID
- Program ebpf.ProgramID
- }
- // RawLink is the low-level API to bpf_link.
- //
- // You should consider using the higher level interfaces in this
- // package instead.
- type RawLink struct {
- fd *internal.FD
- }
- // AttachRawLink creates a raw link.
- func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
- if err := haveBPFLink(); err != nil {
- return nil, err
- }
- if opts.Target < 0 {
- return nil, fmt.Errorf("invalid target: %s", internal.ErrClosedFd)
- }
- progFd := opts.Program.FD()
- if progFd < 0 {
- return nil, fmt.Errorf("invalid program: %s", internal.ErrClosedFd)
- }
- attr := bpfLinkCreateAttr{
- targetFd: uint32(opts.Target),
- progFd: uint32(progFd),
- attachType: opts.Attach,
- }
- fd, err := bpfLinkCreate(&attr)
- if err != nil {
- return nil, fmt.Errorf("can't create link: %s", err)
- }
- return &RawLink{fd}, nil
- }
- // LoadPinnedRawLink loads a persisted link from a bpffs.
- func LoadPinnedRawLink(fileName string) (*RawLink, error) {
- return loadPinnedRawLink(fileName, UnspecifiedType)
- }
- func loadPinnedRawLink(fileName string, typ Type) (*RawLink, error) {
- fd, err := internal.BPFObjGet(fileName)
- if err != nil {
- return nil, fmt.Errorf("load pinned link: %s", err)
- }
- link := &RawLink{fd}
- if typ == UnspecifiedType {
- return link, nil
- }
- info, err := link.Info()
- if err != nil {
- link.Close()
- return nil, fmt.Errorf("get pinned link info: %s", err)
- }
- if info.Type != typ {
- link.Close()
- return nil, fmt.Errorf("link type %v doesn't match %v", info.Type, typ)
- }
- return link, nil
- }
- func (l *RawLink) isLink() {}
- // FD returns the raw file descriptor.
- func (l *RawLink) FD() int {
- fd, err := l.fd.Value()
- if err != nil {
- return -1
- }
- return int(fd)
- }
- // Close breaks the link.
- //
- // Use Pin if you want to make the link persistent.
- func (l *RawLink) Close() error {
- return l.fd.Close()
- }
- // Pin persists a link past the lifetime of the process.
- //
- // Calling Close on a pinned Link will not break the link
- // until the pin is removed.
- func (l *RawLink) Pin(fileName string) error {
- if err := internal.BPFObjPin(fileName, l.fd); err != nil {
- return fmt.Errorf("can't pin link: %s", err)
- }
- return nil
- }
- // Update implements Link.
- func (l *RawLink) Update(new *ebpf.Program) error {
- return l.UpdateArgs(RawLinkUpdateOptions{
- New: new,
- })
- }
- // RawLinkUpdateOptions control the behaviour of RawLink.UpdateArgs.
- type RawLinkUpdateOptions struct {
- New *ebpf.Program
- Old *ebpf.Program
- Flags uint32
- }
- // UpdateArgs updates a link based on args.
- func (l *RawLink) UpdateArgs(opts RawLinkUpdateOptions) error {
- newFd := opts.New.FD()
- if newFd < 0 {
- return fmt.Errorf("invalid program: %s", internal.ErrClosedFd)
- }
- var oldFd int
- if opts.Old != nil {
- oldFd = opts.Old.FD()
- if oldFd < 0 {
- return fmt.Errorf("invalid replacement program: %s", internal.ErrClosedFd)
- }
- }
- linkFd, err := l.fd.Value()
- if err != nil {
- return fmt.Errorf("can't update link: %s", err)
- }
- attr := bpfLinkUpdateAttr{
- linkFd: linkFd,
- newProgFd: uint32(newFd),
- oldProgFd: uint32(oldFd),
- flags: opts.Flags,
- }
- return bpfLinkUpdate(&attr)
- }
- // struct bpf_link_info
- type bpfLinkInfo struct {
- typ uint32
- id uint32
- prog_id uint32
- }
- // Info returns metadata about the link.
- func (l *RawLink) Info() (*RawLinkInfo, error) {
- var info bpfLinkInfo
- err := internal.BPFObjGetInfoByFD(l.fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
- if err != nil {
- return nil, fmt.Errorf("link info: %s", err)
- }
- return &RawLinkInfo{
- Type(info.typ),
- ID(info.id),
- ebpf.ProgramID(info.prog_id),
- }, nil
- }
|