...

Source file src/github.com/cilium/ebpf/link/link.go

Documentation: github.com/cilium/ebpf/link

     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  }
   314  

View as plain text