link.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. package link
  2. import (
  3. "fmt"
  4. "unsafe"
  5. "github.com/cilium/ebpf"
  6. "github.com/cilium/ebpf/internal"
  7. "github.com/cilium/ebpf/internal/btf"
  8. )
  9. var ErrNotSupported = internal.ErrNotSupported
  10. // Link represents a Program attached to a BPF hook.
  11. type Link interface {
  12. // Replace the current program with a new program.
  13. //
  14. // Passing a nil program is an error. May return an error wrapping ErrNotSupported.
  15. Update(*ebpf.Program) error
  16. // Persist a link by pinning it into a bpffs.
  17. //
  18. // May return an error wrapping ErrNotSupported.
  19. Pin(string) error
  20. // Undo a previous call to Pin.
  21. //
  22. // May return an error wrapping ErrNotSupported.
  23. Unpin() error
  24. // Close frees resources.
  25. //
  26. // The link will be broken unless it has been successfully pinned.
  27. // A link may continue past the lifetime of the process if Close is
  28. // not called.
  29. Close() error
  30. // Prevent external users from implementing this interface.
  31. isLink()
  32. }
  33. // ID uniquely identifies a BPF link.
  34. type ID uint32
  35. // RawLinkOptions control the creation of a raw link.
  36. type RawLinkOptions struct {
  37. // File descriptor to attach to. This differs for each attach type.
  38. Target int
  39. // Program to attach.
  40. Program *ebpf.Program
  41. // Attach must match the attach type of Program.
  42. Attach ebpf.AttachType
  43. // BTF is the BTF of the attachment target.
  44. BTF btf.TypeID
  45. }
  46. // RawLinkInfo contains metadata on a link.
  47. type RawLinkInfo struct {
  48. Type Type
  49. ID ID
  50. Program ebpf.ProgramID
  51. }
  52. // RawLink is the low-level API to bpf_link.
  53. //
  54. // You should consider using the higher level interfaces in this
  55. // package instead.
  56. type RawLink struct {
  57. fd *internal.FD
  58. pinnedPath string
  59. }
  60. // AttachRawLink creates a raw link.
  61. func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
  62. if err := haveBPFLink(); err != nil {
  63. return nil, err
  64. }
  65. if opts.Target < 0 {
  66. return nil, fmt.Errorf("invalid target: %s", internal.ErrClosedFd)
  67. }
  68. progFd := opts.Program.FD()
  69. if progFd < 0 {
  70. return nil, fmt.Errorf("invalid program: %s", internal.ErrClosedFd)
  71. }
  72. attr := bpfLinkCreateAttr{
  73. targetFd: uint32(opts.Target),
  74. progFd: uint32(progFd),
  75. attachType: opts.Attach,
  76. targetBTFID: uint32(opts.BTF),
  77. }
  78. fd, err := bpfLinkCreate(&attr)
  79. if err != nil {
  80. return nil, fmt.Errorf("can't create link: %s", err)
  81. }
  82. return &RawLink{fd, ""}, nil
  83. }
  84. // LoadPinnedRawLink loads a persisted link from a bpffs.
  85. //
  86. // Returns an error if the pinned link type doesn't match linkType. Pass
  87. // UnspecifiedType to disable this behaviour.
  88. func LoadPinnedRawLink(fileName string, linkType Type, opts *ebpf.LoadPinOptions) (*RawLink, error) {
  89. fd, err := internal.BPFObjGet(fileName, opts.Marshal())
  90. if err != nil {
  91. return nil, fmt.Errorf("load pinned link: %w", err)
  92. }
  93. link := &RawLink{fd, fileName}
  94. if linkType == UnspecifiedType {
  95. return link, nil
  96. }
  97. info, err := link.Info()
  98. if err != nil {
  99. link.Close()
  100. return nil, fmt.Errorf("get pinned link info: %s", err)
  101. }
  102. if info.Type != linkType {
  103. link.Close()
  104. return nil, fmt.Errorf("link type %v doesn't match %v", info.Type, linkType)
  105. }
  106. return link, nil
  107. }
  108. func (l *RawLink) isLink() {}
  109. // FD returns the raw file descriptor.
  110. func (l *RawLink) FD() int {
  111. fd, err := l.fd.Value()
  112. if err != nil {
  113. return -1
  114. }
  115. return int(fd)
  116. }
  117. // Close breaks the link.
  118. //
  119. // Use Pin if you want to make the link persistent.
  120. func (l *RawLink) Close() error {
  121. return l.fd.Close()
  122. }
  123. // Pin persists a link past the lifetime of the process.
  124. //
  125. // Calling Close on a pinned Link will not break the link
  126. // until the pin is removed.
  127. func (l *RawLink) Pin(fileName string) error {
  128. if err := internal.Pin(l.pinnedPath, fileName, l.fd); err != nil {
  129. return err
  130. }
  131. l.pinnedPath = fileName
  132. return nil
  133. }
  134. // Unpin implements the Link interface.
  135. func (l *RawLink) Unpin() error {
  136. if err := internal.Unpin(l.pinnedPath); err != nil {
  137. return err
  138. }
  139. l.pinnedPath = ""
  140. return nil
  141. }
  142. // Update implements the Link interface.
  143. func (l *RawLink) Update(new *ebpf.Program) error {
  144. return l.UpdateArgs(RawLinkUpdateOptions{
  145. New: new,
  146. })
  147. }
  148. // RawLinkUpdateOptions control the behaviour of RawLink.UpdateArgs.
  149. type RawLinkUpdateOptions struct {
  150. New *ebpf.Program
  151. Old *ebpf.Program
  152. Flags uint32
  153. }
  154. // UpdateArgs updates a link based on args.
  155. func (l *RawLink) UpdateArgs(opts RawLinkUpdateOptions) error {
  156. newFd := opts.New.FD()
  157. if newFd < 0 {
  158. return fmt.Errorf("invalid program: %s", internal.ErrClosedFd)
  159. }
  160. var oldFd int
  161. if opts.Old != nil {
  162. oldFd = opts.Old.FD()
  163. if oldFd < 0 {
  164. return fmt.Errorf("invalid replacement program: %s", internal.ErrClosedFd)
  165. }
  166. }
  167. linkFd, err := l.fd.Value()
  168. if err != nil {
  169. return fmt.Errorf("can't update link: %s", err)
  170. }
  171. attr := bpfLinkUpdateAttr{
  172. linkFd: linkFd,
  173. newProgFd: uint32(newFd),
  174. oldProgFd: uint32(oldFd),
  175. flags: opts.Flags,
  176. }
  177. return bpfLinkUpdate(&attr)
  178. }
  179. // struct bpf_link_info
  180. type bpfLinkInfo struct {
  181. typ uint32
  182. id uint32
  183. prog_id uint32
  184. }
  185. // Info returns metadata about the link.
  186. func (l *RawLink) Info() (*RawLinkInfo, error) {
  187. var info bpfLinkInfo
  188. err := internal.BPFObjGetInfoByFD(l.fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
  189. if err != nil {
  190. return nil, fmt.Errorf("link info: %s", err)
  191. }
  192. return &RawLinkInfo{
  193. Type(info.typ),
  194. ID(info.id),
  195. ebpf.ProgramID(info.prog_id),
  196. }, nil
  197. }