syscalls.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. package ebpf
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "github.com/cilium/ebpf/asm"
  7. "github.com/cilium/ebpf/internal"
  8. "github.com/cilium/ebpf/internal/sys"
  9. "github.com/cilium/ebpf/internal/unix"
  10. )
  11. // invalidBPFObjNameChar returns true if char may not appear in
  12. // a BPF object name.
  13. func invalidBPFObjNameChar(char rune) bool {
  14. dotAllowed := objNameAllowsDot() == nil
  15. switch {
  16. case char >= 'A' && char <= 'Z':
  17. return false
  18. case char >= 'a' && char <= 'z':
  19. return false
  20. case char >= '0' && char <= '9':
  21. return false
  22. case dotAllowed && char == '.':
  23. return false
  24. case char == '_':
  25. return false
  26. default:
  27. return true
  28. }
  29. }
  30. func progLoad(insns asm.Instructions, typ ProgramType, license string) (*sys.FD, error) {
  31. buf := bytes.NewBuffer(make([]byte, 0, insns.Size()))
  32. if err := insns.Marshal(buf, internal.NativeEndian); err != nil {
  33. return nil, err
  34. }
  35. bytecode := buf.Bytes()
  36. return sys.ProgLoad(&sys.ProgLoadAttr{
  37. ProgType: sys.ProgType(typ),
  38. License: sys.NewStringPointer(license),
  39. Insns: sys.NewSlicePointer(bytecode),
  40. InsnCnt: uint32(len(bytecode) / asm.InstructionSize),
  41. })
  42. }
  43. var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() error {
  44. _, err := sys.MapCreate(&sys.MapCreateAttr{
  45. MapType: sys.MapType(ArrayOfMaps),
  46. KeySize: 4,
  47. ValueSize: 4,
  48. MaxEntries: 1,
  49. // Invalid file descriptor.
  50. InnerMapFd: ^uint32(0),
  51. })
  52. if errors.Is(err, unix.EINVAL) {
  53. return internal.ErrNotSupported
  54. }
  55. if errors.Is(err, unix.EBADF) {
  56. return nil
  57. }
  58. return err
  59. })
  60. var haveMapMutabilityModifiers = internal.FeatureTest("read- and write-only maps", "5.2", func() error {
  61. // This checks BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG. Since
  62. // BPF_MAP_FREEZE appeared in 5.2 as well we don't do a separate check.
  63. m, err := sys.MapCreate(&sys.MapCreateAttr{
  64. MapType: sys.MapType(Array),
  65. KeySize: 4,
  66. ValueSize: 4,
  67. MaxEntries: 1,
  68. MapFlags: unix.BPF_F_RDONLY_PROG,
  69. })
  70. if err != nil {
  71. return internal.ErrNotSupported
  72. }
  73. _ = m.Close()
  74. return nil
  75. })
  76. var haveMmapableMaps = internal.FeatureTest("mmapable maps", "5.5", func() error {
  77. // This checks BPF_F_MMAPABLE, which appeared in 5.5 for array maps.
  78. m, err := sys.MapCreate(&sys.MapCreateAttr{
  79. MapType: sys.MapType(Array),
  80. KeySize: 4,
  81. ValueSize: 4,
  82. MaxEntries: 1,
  83. MapFlags: unix.BPF_F_MMAPABLE,
  84. })
  85. if err != nil {
  86. return internal.ErrNotSupported
  87. }
  88. _ = m.Close()
  89. return nil
  90. })
  91. var haveInnerMaps = internal.FeatureTest("inner maps", "5.10", func() error {
  92. // This checks BPF_F_INNER_MAP, which appeared in 5.10.
  93. m, err := sys.MapCreate(&sys.MapCreateAttr{
  94. MapType: sys.MapType(Array),
  95. KeySize: 4,
  96. ValueSize: 4,
  97. MaxEntries: 1,
  98. MapFlags: unix.BPF_F_INNER_MAP,
  99. })
  100. if err != nil {
  101. return internal.ErrNotSupported
  102. }
  103. _ = m.Close()
  104. return nil
  105. })
  106. var haveNoPreallocMaps = internal.FeatureTest("prealloc maps", "4.6", func() error {
  107. // This checks BPF_F_NO_PREALLOC, which appeared in 4.6.
  108. m, err := sys.MapCreate(&sys.MapCreateAttr{
  109. MapType: sys.MapType(Hash),
  110. KeySize: 4,
  111. ValueSize: 4,
  112. MaxEntries: 1,
  113. MapFlags: unix.BPF_F_NO_PREALLOC,
  114. })
  115. if err != nil {
  116. return internal.ErrNotSupported
  117. }
  118. _ = m.Close()
  119. return nil
  120. })
  121. func wrapMapError(err error) error {
  122. if err == nil {
  123. return nil
  124. }
  125. if errors.Is(err, unix.ENOENT) {
  126. return sys.Error(ErrKeyNotExist, unix.ENOENT)
  127. }
  128. if errors.Is(err, unix.EEXIST) {
  129. return sys.Error(ErrKeyExist, unix.EEXIST)
  130. }
  131. if errors.Is(err, unix.ENOTSUPP) {
  132. return sys.Error(ErrNotSupported, unix.ENOTSUPP)
  133. }
  134. if errors.Is(err, unix.E2BIG) {
  135. return fmt.Errorf("key too big for map: %w", err)
  136. }
  137. return err
  138. }
  139. var haveObjName = internal.FeatureTest("object names", "4.15", func() error {
  140. attr := sys.MapCreateAttr{
  141. MapType: sys.MapType(Array),
  142. KeySize: 4,
  143. ValueSize: 4,
  144. MaxEntries: 1,
  145. MapName: sys.NewObjName("feature_test"),
  146. }
  147. fd, err := sys.MapCreate(&attr)
  148. if err != nil {
  149. return internal.ErrNotSupported
  150. }
  151. _ = fd.Close()
  152. return nil
  153. })
  154. var objNameAllowsDot = internal.FeatureTest("dot in object names", "5.2", func() error {
  155. if err := haveObjName(); err != nil {
  156. return err
  157. }
  158. attr := sys.MapCreateAttr{
  159. MapType: sys.MapType(Array),
  160. KeySize: 4,
  161. ValueSize: 4,
  162. MaxEntries: 1,
  163. MapName: sys.NewObjName(".test"),
  164. }
  165. fd, err := sys.MapCreate(&attr)
  166. if err != nil {
  167. return internal.ErrNotSupported
  168. }
  169. _ = fd.Close()
  170. return nil
  171. })
  172. var haveBatchAPI = internal.FeatureTest("map batch api", "5.6", func() error {
  173. var maxEntries uint32 = 2
  174. attr := sys.MapCreateAttr{
  175. MapType: sys.MapType(Hash),
  176. KeySize: 4,
  177. ValueSize: 4,
  178. MaxEntries: maxEntries,
  179. }
  180. fd, err := sys.MapCreate(&attr)
  181. if err != nil {
  182. return internal.ErrNotSupported
  183. }
  184. defer fd.Close()
  185. keys := []uint32{1, 2}
  186. values := []uint32{3, 4}
  187. kp, _ := marshalPtr(keys, 8)
  188. vp, _ := marshalPtr(values, 8)
  189. err = sys.MapUpdateBatch(&sys.MapUpdateBatchAttr{
  190. MapFd: fd.Uint(),
  191. Keys: kp,
  192. Values: vp,
  193. Count: maxEntries,
  194. })
  195. if err != nil {
  196. return internal.ErrNotSupported
  197. }
  198. return nil
  199. })
  200. var haveProbeReadKernel = internal.FeatureTest("bpf_probe_read_kernel", "5.5", func() error {
  201. insns := asm.Instructions{
  202. asm.Mov.Reg(asm.R1, asm.R10),
  203. asm.Add.Imm(asm.R1, -8),
  204. asm.Mov.Imm(asm.R2, 8),
  205. asm.Mov.Imm(asm.R3, 0),
  206. asm.FnProbeReadKernel.Call(),
  207. asm.Return(),
  208. }
  209. fd, err := progLoad(insns, Kprobe, "GPL")
  210. if err != nil {
  211. return internal.ErrNotSupported
  212. }
  213. _ = fd.Close()
  214. return nil
  215. })
  216. var haveBPFToBPFCalls = internal.FeatureTest("bpf2bpf calls", "4.16", func() error {
  217. insns := asm.Instructions{
  218. asm.Call.Label("prog2").WithSymbol("prog1"),
  219. asm.Return(),
  220. asm.Mov.Imm(asm.R0, 0).WithSymbol("prog2"),
  221. asm.Return(),
  222. }
  223. fd, err := progLoad(insns, SocketFilter, "MIT")
  224. if errors.Is(err, unix.EINVAL) {
  225. return internal.ErrNotSupported
  226. }
  227. if err != nil {
  228. return err
  229. }
  230. _ = fd.Close()
  231. return nil
  232. })