github.com/cilium/ebpf@v0.16.0/link/link.go (about)

     1  package link
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     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  // NewLinkFromFD creates a link from a raw fd.
    50  //
    51  // Deprecated: use [NewFromFD] instead.
    52  func NewLinkFromFD(fd int) (Link, error) {
    53  	return NewFromFD(fd)
    54  }
    55  
    56  // NewFromFD creates a link from a raw fd.
    57  //
    58  // You should not use fd after calling this function.
    59  func NewFromFD(fd int) (Link, error) {
    60  	sysFD, err := sys.NewFD(fd)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	return wrapRawLink(&RawLink{fd: sysFD})
    66  }
    67  
    68  // NewFromID returns the link associated with the given id.
    69  //
    70  // Returns ErrNotExist if there is no link with the given id.
    71  func NewFromID(id ID) (Link, error) {
    72  	getFdAttr := &sys.LinkGetFdByIdAttr{Id: id}
    73  	fd, err := sys.LinkGetFdById(getFdAttr)
    74  	if err != nil {
    75  		return nil, fmt.Errorf("get link fd from ID %d: %w", id, err)
    76  	}
    77  
    78  	return wrapRawLink(&RawLink{fd, ""})
    79  }
    80  
    81  // LoadPinnedLink loads a link that was persisted into a bpffs.
    82  func LoadPinnedLink(fileName string, opts *ebpf.LoadPinOptions) (Link, error) {
    83  	raw, err := loadPinnedRawLink(fileName, opts)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  
    88  	return wrapRawLink(raw)
    89  }
    90  
    91  // wrap a RawLink in a more specific type if possible.
    92  //
    93  // The function takes ownership of raw and closes it on error.
    94  func wrapRawLink(raw *RawLink) (_ Link, err error) {
    95  	defer func() {
    96  		if err != nil {
    97  			raw.Close()
    98  		}
    99  	}()
   100  
   101  	info, err := raw.Info()
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  
   106  	switch info.Type {
   107  	case RawTracepointType:
   108  		return &rawTracepoint{*raw}, nil
   109  	case TracingType:
   110  		return &tracing{*raw}, nil
   111  	case CgroupType:
   112  		return &linkCgroup{*raw}, nil
   113  	case IterType:
   114  		return &Iter{*raw}, nil
   115  	case NetNsType:
   116  		return &NetNsLink{*raw}, nil
   117  	case KprobeMultiType:
   118  		return &kprobeMultiLink{*raw}, nil
   119  	case UprobeMultiType:
   120  		return &uprobeMultiLink{*raw}, nil
   121  	case PerfEventType:
   122  		return &perfEventLink{*raw, nil}, nil
   123  	case TCXType:
   124  		return &tcxLink{*raw}, nil
   125  	case NetfilterType:
   126  		return &netfilterLink{*raw}, nil
   127  	case NetkitType:
   128  		return &netkitLink{*raw}, nil
   129  	case XDPType:
   130  		return &xdpLink{*raw}, nil
   131  	default:
   132  		return raw, nil
   133  	}
   134  }
   135  
   136  // ID uniquely identifies a BPF link.
   137  type ID = sys.LinkID
   138  
   139  // RawLinkOptions control the creation of a raw link.
   140  type RawLinkOptions struct {
   141  	// File descriptor to attach to. This differs for each attach type.
   142  	Target int
   143  	// Program to attach.
   144  	Program *ebpf.Program
   145  	// Attach must match the attach type of Program.
   146  	Attach ebpf.AttachType
   147  	// BTF is the BTF of the attachment target.
   148  	BTF btf.TypeID
   149  	// Flags control the attach behaviour.
   150  	Flags uint32
   151  }
   152  
   153  // Info contains metadata on a link.
   154  type Info struct {
   155  	Type    Type
   156  	ID      ID
   157  	Program ebpf.ProgramID
   158  	extra   interface{}
   159  }
   160  
   161  type TracingInfo struct {
   162  	AttachType  sys.AttachType
   163  	TargetObjId uint32
   164  	TargetBtfId sys.TypeID
   165  }
   166  
   167  type CgroupInfo struct {
   168  	CgroupId   uint64
   169  	AttachType sys.AttachType
   170  	_          [4]byte
   171  }
   172  
   173  type NetNsInfo struct {
   174  	NetnsIno   uint32
   175  	AttachType sys.AttachType
   176  }
   177  
   178  type TCXInfo struct {
   179  	Ifindex    uint32
   180  	AttachType sys.AttachType
   181  }
   182  
   183  type XDPInfo struct {
   184  	Ifindex uint32
   185  }
   186  
   187  type NetfilterInfo struct {
   188  	Pf       uint32
   189  	Hooknum  uint32
   190  	Priority int32
   191  	Flags    uint32
   192  }
   193  
   194  type NetkitInfo struct {
   195  	Ifindex    uint32
   196  	AttachType sys.AttachType
   197  }
   198  
   199  type KprobeMultiInfo struct {
   200  	count  uint32
   201  	flags  uint32
   202  	missed uint64
   203  }
   204  
   205  // AddressCount is the number of addresses hooked by the kprobe.
   206  func (kpm *KprobeMultiInfo) AddressCount() (uint32, bool) {
   207  	return kpm.count, kpm.count > 0
   208  }
   209  
   210  func (kpm *KprobeMultiInfo) Flags() (uint32, bool) {
   211  	return kpm.flags, kpm.count > 0
   212  }
   213  
   214  func (kpm *KprobeMultiInfo) Missed() (uint64, bool) {
   215  	return kpm.missed, kpm.count > 0
   216  }
   217  
   218  type PerfEventInfo struct {
   219  	Type  sys.PerfEventType
   220  	extra interface{}
   221  }
   222  
   223  func (r *PerfEventInfo) Kprobe() *KprobeInfo {
   224  	e, _ := r.extra.(*KprobeInfo)
   225  	return e
   226  }
   227  
   228  type KprobeInfo struct {
   229  	address uint64
   230  	missed  uint64
   231  }
   232  
   233  func (kp *KprobeInfo) Address() (uint64, bool) {
   234  	return kp.address, kp.address > 0
   235  }
   236  
   237  func (kp *KprobeInfo) Missed() (uint64, bool) {
   238  	return kp.missed, kp.address > 0
   239  }
   240  
   241  // Tracing returns tracing type-specific link info.
   242  //
   243  // Returns nil if the type-specific link info isn't available.
   244  func (r Info) Tracing() *TracingInfo {
   245  	e, _ := r.extra.(*TracingInfo)
   246  	return e
   247  }
   248  
   249  // Cgroup returns cgroup type-specific link info.
   250  //
   251  // Returns nil if the type-specific link info isn't available.
   252  func (r Info) Cgroup() *CgroupInfo {
   253  	e, _ := r.extra.(*CgroupInfo)
   254  	return e
   255  }
   256  
   257  // NetNs returns netns type-specific link info.
   258  //
   259  // Returns nil if the type-specific link info isn't available.
   260  func (r Info) NetNs() *NetNsInfo {
   261  	e, _ := r.extra.(*NetNsInfo)
   262  	return e
   263  }
   264  
   265  // XDP returns XDP type-specific link info.
   266  //
   267  // Returns nil if the type-specific link info isn't available.
   268  func (r Info) XDP() *XDPInfo {
   269  	e, _ := r.extra.(*XDPInfo)
   270  	return e
   271  }
   272  
   273  // TCX returns TCX type-specific link info.
   274  //
   275  // Returns nil if the type-specific link info isn't available.
   276  func (r Info) TCX() *TCXInfo {
   277  	e, _ := r.extra.(*TCXInfo)
   278  	return e
   279  }
   280  
   281  // Netfilter returns netfilter type-specific link info.
   282  //
   283  // Returns nil if the type-specific link info isn't available.
   284  func (r Info) Netfilter() *NetfilterInfo {
   285  	e, _ := r.extra.(*NetfilterInfo)
   286  	return e
   287  }
   288  
   289  // Netkit returns netkit type-specific link info.
   290  //
   291  // Returns nil if the type-specific link info isn't available.
   292  func (r Info) Netkit() *NetkitInfo {
   293  	e, _ := r.extra.(*NetkitInfo)
   294  	return e
   295  }
   296  
   297  // KprobeMulti returns kprobe-multi type-specific link info.
   298  //
   299  // Returns nil if the type-specific link info isn't available.
   300  func (r Info) KprobeMulti() *KprobeMultiInfo {
   301  	e, _ := r.extra.(*KprobeMultiInfo)
   302  	return e
   303  }
   304  
   305  // PerfEvent returns perf-event type-specific link info.
   306  //
   307  // Returns nil if the type-specific link info isn't available.
   308  func (r Info) PerfEvent() *PerfEventInfo {
   309  	e, _ := r.extra.(*PerfEventInfo)
   310  	return e
   311  }
   312  
   313  // RawLink is the low-level API to bpf_link.
   314  //
   315  // You should consider using the higher level interfaces in this
   316  // package instead.
   317  type RawLink struct {
   318  	fd         *sys.FD
   319  	pinnedPath string
   320  }
   321  
   322  // AttachRawLink creates a raw link.
   323  func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
   324  	if err := haveBPFLink(); err != nil {
   325  		return nil, err
   326  	}
   327  
   328  	if opts.Target < 0 {
   329  		return nil, fmt.Errorf("invalid target: %s", sys.ErrClosedFd)
   330  	}
   331  
   332  	progFd := opts.Program.FD()
   333  	if progFd < 0 {
   334  		return nil, fmt.Errorf("invalid program: %s", sys.ErrClosedFd)
   335  	}
   336  
   337  	attr := sys.LinkCreateAttr{
   338  		TargetFd:    uint32(opts.Target),
   339  		ProgFd:      uint32(progFd),
   340  		AttachType:  sys.AttachType(opts.Attach),
   341  		TargetBtfId: opts.BTF,
   342  		Flags:       opts.Flags,
   343  	}
   344  	fd, err := sys.LinkCreate(&attr)
   345  	if err != nil {
   346  		return nil, fmt.Errorf("create link: %w", err)
   347  	}
   348  
   349  	return &RawLink{fd, ""}, nil
   350  }
   351  
   352  func loadPinnedRawLink(fileName string, opts *ebpf.LoadPinOptions) (*RawLink, error) {
   353  	fd, err := sys.ObjGet(&sys.ObjGetAttr{
   354  		Pathname:  sys.NewStringPointer(fileName),
   355  		FileFlags: opts.Marshal(),
   356  	})
   357  	if err != nil {
   358  		return nil, fmt.Errorf("load pinned link: %w", err)
   359  	}
   360  
   361  	return &RawLink{fd, fileName}, nil
   362  }
   363  
   364  func (l *RawLink) isLink() {}
   365  
   366  // FD returns the raw file descriptor.
   367  func (l *RawLink) FD() int {
   368  	return l.fd.Int()
   369  }
   370  
   371  // Close breaks the link.
   372  //
   373  // Use Pin if you want to make the link persistent.
   374  func (l *RawLink) Close() error {
   375  	return l.fd.Close()
   376  }
   377  
   378  // Pin persists a link past the lifetime of the process.
   379  //
   380  // Calling Close on a pinned Link will not break the link
   381  // until the pin is removed.
   382  func (l *RawLink) Pin(fileName string) error {
   383  	if err := internal.Pin(l.pinnedPath, fileName, l.fd); err != nil {
   384  		return err
   385  	}
   386  	l.pinnedPath = fileName
   387  	return nil
   388  }
   389  
   390  // Unpin implements the Link interface.
   391  func (l *RawLink) Unpin() error {
   392  	if err := internal.Unpin(l.pinnedPath); err != nil {
   393  		return err
   394  	}
   395  	l.pinnedPath = ""
   396  	return nil
   397  }
   398  
   399  // IsPinned returns true if the Link has a non-empty pinned path.
   400  func (l *RawLink) IsPinned() bool {
   401  	return l.pinnedPath != ""
   402  }
   403  
   404  // Update implements the Link interface.
   405  func (l *RawLink) Update(new *ebpf.Program) error {
   406  	return l.UpdateArgs(RawLinkUpdateOptions{
   407  		New: new,
   408  	})
   409  }
   410  
   411  // RawLinkUpdateOptions control the behaviour of RawLink.UpdateArgs.
   412  type RawLinkUpdateOptions struct {
   413  	New   *ebpf.Program
   414  	Old   *ebpf.Program
   415  	Flags uint32
   416  }
   417  
   418  // UpdateArgs updates a link based on args.
   419  func (l *RawLink) UpdateArgs(opts RawLinkUpdateOptions) error {
   420  	newFd := opts.New.FD()
   421  	if newFd < 0 {
   422  		return fmt.Errorf("invalid program: %s", sys.ErrClosedFd)
   423  	}
   424  
   425  	var oldFd int
   426  	if opts.Old != nil {
   427  		oldFd = opts.Old.FD()
   428  		if oldFd < 0 {
   429  			return fmt.Errorf("invalid replacement program: %s", sys.ErrClosedFd)
   430  		}
   431  	}
   432  
   433  	attr := sys.LinkUpdateAttr{
   434  		LinkFd:    l.fd.Uint(),
   435  		NewProgFd: uint32(newFd),
   436  		OldProgFd: uint32(oldFd),
   437  		Flags:     opts.Flags,
   438  	}
   439  	return sys.LinkUpdate(&attr)
   440  }
   441  
   442  // Info returns metadata about the link.
   443  //
   444  // Linktype specific metadata is not included and can be retrieved
   445  // via the linktype specific Info() method.
   446  func (l *RawLink) Info() (*Info, error) {
   447  	var info sys.LinkInfo
   448  
   449  	if err := sys.ObjInfo(l.fd, &info); err != nil {
   450  		return nil, fmt.Errorf("link info: %s", err)
   451  	}
   452  
   453  	return &Info{
   454  		info.Type,
   455  		info.Id,
   456  		ebpf.ProgramID(info.ProgId),
   457  		nil,
   458  	}, nil
   459  }
   460  
   461  // Iterator allows iterating over links attached into the kernel.
   462  type Iterator struct {
   463  	// The ID of the current link. Only valid after a call to Next
   464  	ID ID
   465  	// The current link. Only valid until a call to Next.
   466  	// See Take if you want to retain the link.
   467  	Link Link
   468  	err  error
   469  }
   470  
   471  // Next retrieves the next link.
   472  //
   473  // Returns true if another link was found. Call [Iterator.Err] after the function returns false.
   474  func (it *Iterator) Next() bool {
   475  	id := it.ID
   476  	for {
   477  		getIdAttr := &sys.LinkGetNextIdAttr{Id: id}
   478  		err := sys.LinkGetNextId(getIdAttr)
   479  		if errors.Is(err, os.ErrNotExist) {
   480  			// There are no more links.
   481  			break
   482  		} else if err != nil {
   483  			it.err = fmt.Errorf("get next link ID: %w", err)
   484  			break
   485  		}
   486  
   487  		id = getIdAttr.NextId
   488  		l, err := NewFromID(id)
   489  		if errors.Is(err, os.ErrNotExist) {
   490  			// Couldn't load the link fast enough. Try next ID.
   491  			continue
   492  		} else if err != nil {
   493  			it.err = fmt.Errorf("get link for ID %d: %w", id, err)
   494  			break
   495  		}
   496  
   497  		if it.Link != nil {
   498  			it.Link.Close()
   499  		}
   500  		it.ID, it.Link = id, l
   501  		return true
   502  	}
   503  
   504  	// No more links or we encountered an error.
   505  	if it.Link != nil {
   506  		it.Link.Close()
   507  	}
   508  	it.Link = nil
   509  	return false
   510  }
   511  
   512  // Take the ownership of the current link.
   513  //
   514  // It's the callers responsibility to close the link.
   515  func (it *Iterator) Take() Link {
   516  	l := it.Link
   517  	it.Link = nil
   518  	return l
   519  }
   520  
   521  // Err returns an error if iteration failed for some reason.
   522  func (it *Iterator) Err() error {
   523  	return it.err
   524  }
   525  
   526  func (it *Iterator) Close() {
   527  	if it.Link != nil {
   528  		it.Link.Close()
   529  	}
   530  }