github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/bpfsys/syscall.go (about) 1 package bpfsys 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/dylandreimerink/gobpfld/bpftypes" 8 "github.com/dylandreimerink/gobpfld/internal/syscall" 9 "github.com/dylandreimerink/gobpfld/kernelsupport" 10 "golang.org/x/sys/unix" 11 ) 12 13 // ErrNotSupported is returned when attempting to use a feature that is not supported 14 // by the kernel version on which the program is executed. 15 var ErrNotSupported = errors.New("feature not supported by kernel version") 16 17 type BPFSyscallError syscall.Error 18 19 func (e *BPFSyscallError) Error() string { 20 var sysErr syscall.Error = syscall.Error(*e) 21 return sysErr.Error() 22 } 23 24 // BPFfd is an alias of a file descriptor returned by bpf to identify a map, program or link. 25 // Since not all the usual file descriptor functions are available to these types of fds. 26 // 27 // eBPF objects (maps and programs) can be shared between processes. 28 // * After **fork**\ (2), the child inherits file descriptors 29 // referring to the same eBPF objects. 30 // * File descriptors referring to eBPF objects can be transferred over 31 // **unix**\ (7) domain sockets. 32 // * File descriptors referring to eBPF objects can be duplicated in the 33 // usual way, using **dup**\ (2) and similar calls. 34 // * File descriptors referring to eBPF objects can be pinned to the 35 // filesystem using the **BPF_OBJ_PIN** command of **bpf**\ (2). 36 // 37 // An eBPF object is deallocated only after all file descriptors referring 38 // to the object have been closed and no references remain pinned to the 39 // filesystem or attached (for example, bound to a program or device). 40 type BPFfd uint32 41 42 // Close closes a file descriptor 43 func (fd BPFfd) Close() error { 44 err := unix.Close(int(fd)) 45 if err != nil { 46 return err 47 } 48 49 return nil 50 } 51 52 // Bpf is a wrapper around the BPF syscall, so a very low level function. 53 // It is not recommended to use it directly unless you know what you are doing 54 func Bpf(cmd bpftypes.BPFCommand, attr BPFAttribute, size int) (fd BPFfd, err error) { 55 if !kernelsupport.CurrentFeatures.BPF { 56 return 0, fmt.Errorf("eBPF is not supported: %w", ErrNotSupported) 57 } 58 59 r0, err := syscall.Bpf(int(cmd), attr, size) 60 61 return BPFfd(r0), err 62 } 63 64 // Wraps Bpf but discards the first return value 65 func bpfNoReturn(cmd bpftypes.BPFCommand, attr BPFAttribute, size int) error { 66 _, err := Bpf(cmd, attr, size) 67 return err 68 } 69 70 // MapCreate creates a map and return a file descriptor that refers to the 71 // map. The close-on-exec file descriptor flag (see fcntl(2) in linux man pages) 72 // is automatically enabled for the new file descriptor. 73 // 74 // Calling Close on the returned file descriptor will delete the map. 75 func MapCreate(attr *BPFAttrMapCreate) (fd BPFfd, err error) { 76 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIBasic) { 77 return 0, fmt.Errorf("map create not supported: %w", ErrNotSupported) 78 } 79 80 // If the user attempts to use a unsupported feature, tell them to avoid unexpected behavior 81 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapNumaCreate) { 82 if attr.NumaNode != uint32(0) || attr.MapFlags&bpftypes.BPFMapFlagsNUMANode > 0 { 83 return 0, fmt.Errorf("NUMA node can't be specified: %w", ErrNotSupported) 84 } 85 } 86 87 // If the user attempts to use a unsupported feature, tell them to avoid unexpected behavior 88 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapSyscallRW) { 89 if attr.MapFlags&(bpftypes.BPFMapFlagsReadOnly|bpftypes.BPFMapFlagsWriteOnly) > 0 { 90 return 0, fmt.Errorf("map access can't be restricted from syscall side: %w", ErrNotSupported) 91 } 92 } 93 94 // If the user attempts to use a unsupported feature, tell them to avoid unexpected behavior 95 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapName) { 96 if attr.MapName != [16]byte{} { 97 return 0, fmt.Errorf("map name can't be specified: %w", ErrNotSupported) 98 } 99 } 100 101 // If the user attempts to use a unsupported feature, tell them to avoid unexpected behavior 102 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapZeroSeed) { 103 if attr.MapFlags&bpftypes.BPFMapFlagsZeroSeed > 0 { 104 return 0, fmt.Errorf("zero seed flag not supported: %w", ErrNotSupported) 105 } 106 } 107 108 // If the user attempts to use a unsupported feature, tell them to avoid unexpected behavior 109 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapBPFRW) { 110 if attr.MapFlags&(bpftypes.BPFMapFlagsReadOnlyProg|bpftypes.BPFMapFlagsWriteOnlyProg) > 0 { 111 return 0, fmt.Errorf("map access can't be restricted from bpf side: %w", ErrNotSupported) 112 } 113 } 114 115 return Bpf(bpftypes.BPF_MAP_CREATE, attr, int(attr.Size())) 116 } 117 118 // MapLookupElem looks up an element with a given 'Key' in the map referred to by the file descriptor 'MapFD'. 119 // Key must be a pointer to the key value, Value_NextKey must be a pointer to a value which the kernel will overwrite 120 // with the value in the map. 121 // For this call, only a 'Flags' value of 0 or BPFMapElemLock is allowed 122 func MapLookupElem(attr *BPFAttrMapElem) error { 123 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIBasic) { 124 return fmt.Errorf("map lookup not supported: %w", ErrNotSupported) 125 } 126 127 return bpfNoReturn(bpftypes.BPF_MAP_LOOKUP_ELEM, attr, int(attr.Size())) 128 } 129 130 // MapUpdateElem creates or update an element (key/value pair) in a specified map. 131 func MapUpdateElem(attr *BPFAttrMapElem) error { 132 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIBasic) { 133 return fmt.Errorf("map update not supported: %w", ErrNotSupported) 134 } 135 136 err := bpfNoReturn(bpftypes.BPF_MAP_UPDATE_ELEM, attr, int(attr.Size())) 137 if syserr, ok := err.(*BPFSyscallError); ok { 138 syserr.Err = map[unix.Errno]string{ 139 unix.E2BIG: "The number of elements in the map reached the *max_entries* limit specified at map " + 140 "creation time.", 141 unix.EEXIST: "attr.Flags specifies BPFMapElemNoExists and the element with attr.Key already exists " + 142 "in the map.", 143 unix.ENOENT: "attr.Flags specifies BPFMapElemExists and the element with attr.Key does not exist " + 144 "in the map", 145 }[syserr.Errno] 146 return syserr 147 } 148 return err 149 } 150 151 // MapDeleteElem looks up and delete an element by key in a specified map. 152 func MapDeleteElem(attr *BPFAttrMapElem) error { 153 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIBasic) { 154 return fmt.Errorf("map delete not supported: %w", ErrNotSupported) 155 } 156 157 return bpfNoReturn(bpftypes.BPF_MAP_DELETE_ELEM, attr, int(attr.Size())) 158 } 159 160 // MapGetNextKey looks up an element by attr.Key in a specified map and sets the key 161 // of the key of the next element in attr.Value_NextValue. Can be used to iterate over all elements 162 // 163 // The following cases can be used to iterate over all elements of the map: 164 // * If attr.Key is not found, the operation sets the 165 // attr.Value_NextValue pointer to the key of the first element. 166 // * If attr.Key is found, the operation returns sets the 167 // attr.Value_NextValue pointer to the key of the next element. 168 // * If attr.Key is the last element, an error with errno ENOENT(2) is returned. 169 func MapGetNextKey(attr *BPFAttrMapElem) error { 170 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIBasic) { 171 return fmt.Errorf("map get next key not supported: %w", ErrNotSupported) 172 } 173 174 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapGetNextNull) && 175 attr.Value_NextKey == uintptr(0) { 176 177 return fmt.Errorf("NextKey == NULL: %w", ErrNotSupported) 178 } 179 180 err := bpfNoReturn(bpftypes.BPF_MAP_GET_NEXT_KEY, attr, int(attr.Size())) 181 if syserr, ok := err.(*BPFSyscallError); ok { 182 syserr.Err = map[unix.Errno]string{ 183 unix.ENOENT: "element indicated by attr.Key is the last in the map", 184 }[syserr.Errno] 185 return syserr 186 } 187 return err 188 } 189 190 // LoadProgram verifies and loads an eBPF program, returning a new file descriptor associated with the program. 191 // The close-on-exec file descriptor flag (see fcntl(2) in linux man pages) is automatically enabled for 192 // the new file descriptor. 193 // 194 // Calling Close on the returned file descriptor will unload the program. 195 func LoadProgram(attr *BPFAttrProgramLoad) (fd BPFfd, err error) { 196 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIBasic) { 197 return 0, fmt.Errorf("prog load not supported: %w", ErrNotSupported) 198 } 199 200 return Bpf(bpftypes.BPF_PROG_LOAD, attr, int(attr.Size())) 201 } 202 203 // ObjectPin pins an eBPF program or map referred by the specified attr.BPFfd 204 // to the provided attr.Pathname on the filesystem. 205 // 206 // attr.Pathname must not contain a dot ("."). 207 // 208 // On success, attr.Pathname retains a reference to the eBPF object, 209 // preventing deallocation of the object when the original 210 // attr.BPFfd is closed. This allow the eBPF object to live beyond 211 // attr.BPFfd.Close(), and hence the lifetime of the parent 212 // process. 213 // 214 // Applying unix.Unlink or similar calls to the attr.Pathname 215 // unpins the object from the filesystem, removing the reference. 216 // If no other file descriptors or filesystem nodes refer to the 217 // same object, it will be deallocated. 218 // 219 // The filesystem type for the parent directory of attr.Pathname must 220 // be **BPF_FS_MAGIC**. On most systems the /sys/fs/bpf is a BPF_FS_MAGIC directory 221 func ObjectPin(attr *BPFAttrObj) error { 222 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIObjPinGet) { 223 return fmt.Errorf("object pinning not supported: %w", ErrNotSupported) 224 } 225 226 return bpfNoReturn(bpftypes.BPF_OBJ_PIN, attr, int(attr.Size())) 227 } 228 229 // ObjectGet opens a file descriptor for the eBPF object pinned to the specified attr.Pathname 230 func ObjectGet(attr *BPFAttrObj) (fd BPFfd, err error) { 231 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIObjPinGet) { 232 return 0, fmt.Errorf("object get not supported: %w", ErrNotSupported) 233 } 234 235 return Bpf(bpftypes.BPF_OBJ_GET, attr, int(attr.Size())) 236 } 237 238 // ProgramAttach attaches an eBPF program to a attr.TargetFD at the specified attr.AttachType hook. 239 // The attr.AttachType specifies the eBPF attachment point to attach the program to, 240 // and must be one of bpftypes.BPFAttachType. 241 // The attr.AttachBPFFD must be a valid file descriptor for a loaded eBPF program of a cgroup, flow dissector, LIRC, 242 // sockmap or sock_ops type corresponding to the specified attr.AttachType. 243 // 244 // The attr.TargetFD must be a valid file descriptor for a kernel 245 // object which depends on the attach type of attr.AttachBPFFD: 246 // bpftypes.BPF_PROG_TYPE_CGROUP_DEVICE, 247 // bpftypes.BPF_PROG_TYPE_CGROUP_SKB, 248 // bpftypes.BPF_PROG_TYPE_CGROUP_SOCK, 249 // bpftypes.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, 250 // bpftypes.BPF_PROG_TYPE_CGROUP_SOCKOPT, 251 // bpftypes.BPF_PROG_TYPE_CGROUP_SYSCTL, 252 // bpftypes.BPF_PROG_TYPE_SOCK_OPS 253 // Control Group v2 hierarchy with the eBPF controller 254 // enabled. Requires the kernel to be compiled with 255 // CONFIG_CGROUP_BPF. 256 // bpftypes.BPF_PROG_TYPE_FLOW_DISSECTOR 257 // Network namespace (eg /proc/self/ns/net). 258 // bpftypes.BPF_PROG_TYPE_LIRC_MODE2 259 // LIRC device path (eg /dev/lircN). Requires the kernel 260 // to be compiled with CONFIG_BPF_LIRC_MODE2. 261 // bpftypes.BPF_PROG_TYPE_SK_SKB, 262 // bpftypes.BPF_PROG_TYPE_SK_MSG 263 // eBPF map of socket type (eg bpftypes.BPF_MAP_TYPE_SOCKHASH). 264 func ProgramAttach(attr *BPFAttrProgAttachDetach) error { 265 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIProgramAttachDetach) { 266 return fmt.Errorf("program attach not supported: %w", ErrNotSupported) 267 } 268 269 if kfeat, found := attachTypeToKFeat[attr.AttachType]; found { 270 if !kernelsupport.CurrentFeatures.Attach.Has(kfeat) { 271 return fmt.Errorf("program attach type '%s' not supported: %w", attr.AttachType, ErrNotSupported) 272 } 273 } 274 275 return bpfNoReturn(bpftypes.BPF_PROG_ATTACH, attr, int(attr.Size())) 276 } 277 278 var attachTypeToKFeat = map[bpftypes.BPFAttachType]kernelsupport.AttachSupport{ 279 bpftypes.BPF_CGROUP_INET_INGRESS: kernelsupport.KFeatAttachINetIngressEgress, 280 bpftypes.BPF_CGROUP_INET_EGRESS: kernelsupport.KFeatAttachINetIngressEgress, 281 bpftypes.BPF_CGROUP_INET_SOCK_CREATE: kernelsupport.KFeatAttachInetSocketCreate, 282 bpftypes.BPF_CGROUP_SOCK_OPS: kernelsupport.KFeatAttachSocketOps, 283 bpftypes.BPF_SK_SKB_STREAM_PARSER: kernelsupport.KFeatAttachStreamParserVerdict, 284 bpftypes.BPF_SK_SKB_STREAM_VERDICT: kernelsupport.KFeatAttachStreamParserVerdict, 285 bpftypes.BPF_CGROUP_DEVICE: kernelsupport.KFeatAttachCGroupDevice, 286 bpftypes.BPF_SK_MSG_VERDICT: kernelsupport.KFeatAttachSKMsgVerdict, 287 bpftypes.BPF_CGROUP_INET4_BIND: kernelsupport.KFeatAttachCGroupInetBind, 288 bpftypes.BPF_CGROUP_INET6_BIND: kernelsupport.KFeatAttachCGroupInetBind, 289 bpftypes.BPF_CGROUP_INET4_CONNECT: kernelsupport.KFeatAttachCGroupInetConnect, 290 bpftypes.BPF_CGROUP_INET6_CONNECT: kernelsupport.KFeatAttachCGroupInetConnect, 291 bpftypes.BPF_CGROUP_INET4_POST_BIND: kernelsupport.KFeatAttachCGroupInetPostBind, 292 bpftypes.BPF_CGROUP_INET6_POST_BIND: kernelsupport.KFeatAttachCGroupInetPostBind, 293 bpftypes.BPF_CGROUP_UDP4_SENDMSG: kernelsupport.KFeatAttachCGroupUDPSendMsg, 294 bpftypes.BPF_CGROUP_UDP6_SENDMSG: kernelsupport.KFeatAttachCGroupUDPSendMsg, 295 bpftypes.BPF_LIRC_MODE2: kernelsupport.KFeatAttachLIRCMode2, 296 bpftypes.BPF_FLOW_DISSECTOR: kernelsupport.KFeatAttachFlowDissector, 297 bpftypes.BPF_CGROUP_SYSCTL: kernelsupport.KFeatAttachCGroupSysctl, 298 bpftypes.BPF_CGROUP_UDP4_RECVMSG: kernelsupport.KFeatAttachCGroupUDPRecvMsg, 299 bpftypes.BPF_CGROUP_UDP6_RECVMSG: kernelsupport.KFeatAttachCGroupUDPRecvMsg, 300 bpftypes.BPF_CGROUP_GETSOCKOPT: kernelsupport.KFeatAttachCGroupGetSetSocket, 301 bpftypes.BPF_CGROUP_SETSOCKOPT: kernelsupport.KFeatAttachCGroupGetSetSocket, 302 bpftypes.BPF_TRACE_RAW_TP: kernelsupport.KFeatAttachTraceRawTP, 303 bpftypes.BPF_TRACE_FENTRY: kernelsupport.KFeatAttachTraceFentry, 304 bpftypes.BPF_TRACE_FEXIT: kernelsupport.KFeatAttachTraceFExit, 305 bpftypes.BPF_MODIFY_RETURN: kernelsupport.KFeatAttachModifyReturn, 306 bpftypes.BPF_LSM_MAC: kernelsupport.KFeatAttachLSMMAC, 307 bpftypes.BPF_TRACE_ITER: kernelsupport.KFeatAttachTraceIter, 308 bpftypes.BPF_CGROUP_INET4_GETPEERNAME: kernelsupport.KFeatAttachCGroupINetGetPeerName, 309 bpftypes.BPF_CGROUP_INET6_GETPEERNAME: kernelsupport.KFeatAttachCGroupINetGetPeerName, 310 bpftypes.BPF_CGROUP_INET4_GETSOCKNAME: kernelsupport.KFeatAttachCGroupINetGetSocketName, 311 bpftypes.BPF_CGROUP_INET6_GETSOCKNAME: kernelsupport.KFeatAttachCGroupINetGetSocketName, 312 bpftypes.BPF_XDP_DEVMAP: kernelsupport.KFeatAttachXDPDevMap, 313 bpftypes.BPF_CGROUP_INET_SOCK_RELEASE: kernelsupport.KFeatAttachCGroupInetSocketRelease, 314 bpftypes.BPF_XDP_CPUMAP: kernelsupport.KFeatAttachXDPCPUMap, 315 bpftypes.BPF_SK_LOOKUP: kernelsupport.KFeatAttachSKLookup, 316 bpftypes.BPF_XDP: kernelsupport.KFeatAttachXDP, 317 } 318 319 // ProgramDetach detaches the eBPF program associated with the attr.TargetFD at the hook specified by *attach_type*. 320 // The program must have been previously attached using ProgramAttach. 321 func ProgramDetach(attr *BPFAttrProgAttachDetach) error { 322 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIProgramAttachDetach) { 323 return fmt.Errorf("program detach not supported: %w", ErrNotSupported) 324 } 325 326 return bpfNoReturn(bpftypes.BPF_PROG_DETACH, attr, int(attr.Size())) 327 } 328 329 // ProgramTestRun runs the eBPF program associated with the attr.ProgFD a attr.Repeat number of times against 330 // a provided program context attr.CtxIn and data attr.DataIn, and return the modified program context attr.CtxOut, 331 // attr.DataOut (for example, packet data), result of the execution attr.Retval, and attr.Duration of the test run. 332 func ProgramTestRun(attr *BPFAttrProgTestRun) error { 333 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIProgramTestRun) { 334 return fmt.Errorf("program test run not supported: %w", ErrNotSupported) 335 } 336 337 err := bpfNoReturn(bpftypes.BPF_PROG_TEST_RUN, attr, int(attr.Size())) 338 if syserr, ok := err.(*BPFSyscallError); ok { 339 syserr.Err = map[unix.Errno]string{ 340 unix.ENOSPC: "Either attr.DataSizeOut or attr.CtxSizeOut is too small", 341 syscall.ENOTSUPP: "This command is not supported by the program type of the program referred to " + 342 "by attr.ProgFD", 343 }[syserr.Errno] 344 return syserr 345 } 346 347 return err 348 } 349 350 // ProgramGetNextID fetches the next eBPF program currently loaded into the kernel. 351 // Looks for the eBPF program with an id greater than attr.ID and updates attr.NextID on success. 352 // If no other eBPF programs remain with ids higher than attr.ID, an error with errno ENOENT(2) is returned. 353 func ProgramGetNextID(attr *BPFAttrGetID) error { 354 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIProgramGetNextID) { 355 return fmt.Errorf("program get next id not supported: %w", ErrNotSupported) 356 } 357 358 return bpfNoReturn(bpftypes.BPF_PROG_GET_NEXT_ID, attr, int(attr.Size())) 359 } 360 361 // MapGetNextID fetches the next eBPF map currently loaded into the kernel. 362 // Looks for the eBPF map with an id greater than attr.ID and updates attr.NextID on success. 363 // If no other eBPF maps remain with ids higher than attr.ID, an error with errno ENOENT(2) is returned. 364 func MapGetNextID(attr *BPFAttrGetID) error { 365 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapGetNextID) { 366 return fmt.Errorf("map get next id not supported: %w", ErrNotSupported) 367 } 368 369 return bpfNoReturn(bpftypes.BPF_MAP_GET_NEXT_ID, attr, int(attr.Size())) 370 } 371 372 // ProgramGetFDByID opens a file descriptor for the eBPF program corresponding to attr.ID. 373 func ProgramGetFDByID(attr *BPFAttrGetID) (fd BPFfd, err error) { 374 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIProgramGetFDByID) { 375 return 0, fmt.Errorf("program get fd by id not supported: %w", ErrNotSupported) 376 } 377 378 return Bpf(bpftypes.BPF_PROG_GET_FD_BY_ID, attr, int(attr.Size())) 379 } 380 381 // MapGetFDByID queries the kernel for the file descriptor of a map with the given ID. 382 // If successful the syscall will return the file descriptor as the first return value 383 func MapGetFDByID(attr *BPFAttrGetID) (fd BPFfd, err error) { 384 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapGetFDByID) { 385 return 0, fmt.Errorf("map get fd by id not supported: %w", ErrNotSupported) 386 } 387 388 return Bpf(bpftypes.BPF_MAP_GET_FD_BY_ID, attr, int(attr.Size())) 389 } 390 391 // ObjectGetInfoByFD obtains information about the eBPF object corresponding to attr.BPFFD. 392 // Populates up to attr.InfoLen bytes of attr.Info, which will be in one of the following 393 // formats depending on the eBPF object type of attr.BPFFD: 394 // * bpftypes.BPFProgInfo 395 // * bpftypes.BPFMapInfo 396 // * struct bpf_btf_info (TODO make go version of struct in bpftypes) 397 // * struct bpf_link_info (TODO make go version of struct in bpftypes) 398 func ObjectGetInfoByFD(attr *BPFAttrGetInfoFD) error { 399 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIObjectGetInfoByFD) { 400 return fmt.Errorf("object get info by fd not supported: %w", ErrNotSupported) 401 } 402 403 _, errno := Bpf(bpftypes.BPF_OBJ_GET_INFO_BY_FD, attr, int(attr.Size())) 404 return errno 405 } 406 407 // ProgramQuery obtains information about eBPF programs associated with the specified attr.AttachType hook. 408 // The attr.TargetFD must be a valid file descriptor for a kernel object which depends on 409 // the attach type of attr.AttachType: 410 // bpftypes.BPF_PROG_TYPE_CGROUP_DEVICE, 411 // bpftypes.BPF_PROG_TYPE_CGROUP_SKB, 412 // bpftypes.BPF_PROG_TYPE_CGROUP_SOCK, 413 // bpftypes.BPF_PROG_TYPE_CGROUP_SOCK_ADDR, 414 // bpftypes.BPF_PROG_TYPE_CGROUP_SOCKOPT, 415 // bpftypes.BPF_PROG_TYPE_CGROUP_SYSCTL, 416 // bpftypes.BPF_PROG_TYPE_SOCK_OPS 417 // Control Group v2 hierarchy with the eBPF controller 418 // enabled. Requires the kernel to be compiled with 419 // CONFIG_CGROUP_BPF. 420 // bpftypes.BPF_PROG_TYPE_FLOW_DISSECTOR 421 // Network namespace (eg /proc/self/ns/net). 422 // bpftypes.BPF_PROG_TYPE_LIRC_MODE2 423 // LIRC device path (eg /dev/lircN). Requires the kernel 424 // to be compiled with CONFIG_BPF_LIRC_MODE2. 425 // 426 // ProgramQuery always fetches the number of programs 427 // attached and the attr.AttachFlags which were used to attach those 428 // programs. Additionally, if attr.ProgIDs is nonzero and the number 429 // of attached programs is less than attr.ProgCnt, populates 430 // attr.ProgIDs with the eBPF program ids of the programs attached 431 // at attr.TargetFD. 432 // 433 // The following flags may alter the result: 434 // 435 // ProgQueryQueryEffective 436 // Only return information regarding programs which are 437 // currently effective at the specified attr.TargetFD. 438 func ProgramQuery(attr *BPFAttrProgQuery) error { 439 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIProgramQuery) { 440 return fmt.Errorf("program query not supported: %w", ErrNotSupported) 441 } 442 443 return bpfNoReturn(bpftypes.BPF_PROG_QUERY, attr, int(attr.Size())) 444 } 445 446 // RawTracepointOpen attaches an eBPF program to a tracepoint *name* to access kernel 447 // internal arguments of the tracepoint in their raw form. 448 // 449 // The attr.ProgID must be a valid file descriptor associated with 450 // a loaded eBPF program of type bpftypes.BPF_PROG_TYPE_RAW_TRACEPOINT. 451 // 452 // No ABI guarantees are made about the content of tracepoint 453 // arguments exposed to the corresponding eBPF program. 454 // 455 // Applying Close to the file descriptor returned by 456 // RawTracepointOpen will delete the map. 457 func RawTracepointOpen(attr *BPFAttrRawTracepointOpen) (fd BPFfd, err error) { 458 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIRawTracepointOpen) { 459 return 0, fmt.Errorf("raw tracepoint open not supported: %w", ErrNotSupported) 460 } 461 462 return Bpf(bpftypes.BPF_RAW_TRACEPOINT_OPEN, attr, int(attr.Size())) 463 } 464 465 // BTFLoad verifies and loads BPF Type Format (BTF) metadata into the kernel, 466 // returning a new file descriptor associated with the metadata. 467 // BTF is described in more detail at https://www.kernel.org/doc/html/latest/bpf/btf.html. 468 // 469 // The attr.BTF parameter must point to valid memory providing 470 // attr.BTFSize bytes of BTF binary metadata. 471 // 472 // The returned file descriptor can be passed to other 473 // functions such as ProgramLoad or MapCreate to 474 // associate the BTF with those objects. 475 // 476 // Similar toProgramLoad, BTFLoad has optional 477 // parameters to specify a attr.BTFLog, attr.BTFLogSize and 478 // attr.BTFLogLevel which allow the kernel to return freeform log 479 // output regarding the BTF verification process. 480 func BTFLoad(attr *BPFAttrBTFLoad) (fd BPFfd, err error) { 481 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIBTFLoad) { 482 return 0, fmt.Errorf("BTF load not supported: %w", ErrNotSupported) 483 } 484 485 return Bpf(bpftypes.BPF_BTF_LOAD, attr, int(attr.Size())) 486 } 487 488 // BTFGetFDByID opens a file descriptor for the BPF Type Format (BTF) corresponding to attr.ID. 489 func BTFGetFDByID(attr *BPFAttrGetID) error { 490 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIBTFGetFDByID) { 491 return fmt.Errorf("BTF get fd by id not supported: %w", ErrNotSupported) 492 } 493 494 return bpfNoReturn(bpftypes.BPF_BTF_GET_FD_BY_ID, attr, int(attr.Size())) 495 } 496 497 // TaskFDQuery obtains information about eBPF programs associated with the 498 // target process identified by attr.PID and attr.FD. 499 // 500 // If the attr.PID and attr.fd are associated with a tracepoint, kprobe 501 // or uprobe perf event, then the attr.ProgID and attr.FDType will 502 // be populated with the eBPF program id and file descriptor type 503 // of type bpftypes.BPFTaskFDType. If associated with a kprobe or 504 // uprobe, the attr.ProbeOffset and attr.ProbeAddr will also be 505 // populated. Optionally, if attr.Buf is provided, then up to 506 // attr.BufLen bytes of attr.Buf will be populated with the name of 507 // the tracepoint, kprobe or uprobe. 508 // 509 // The resulting attr.ProgID may be introspected in deeper detail 510 // using ProgramGetFDByID and ObjectGetInfoByFD. 511 func TaskFDQuery(attr *BPFAttrTaskFDQuery) error { 512 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPITaskFDQuery) { 513 return fmt.Errorf("task fd query not supported: %w", ErrNotSupported) 514 } 515 516 return bpfNoReturn(bpftypes.BPF_TASK_FD_QUERY, attr, int(attr.Size())) 517 } 518 519 // MapLookupAndDeleteElement looks up an element with the given attr.Key in the map referred to 520 // by the file descriptor attr.MapFD, and if found, delete the element. 521 // 522 // The bpftypes.BPF_MAP_TYPE_QUEUE and bpftypes.BPF_MAP_TYPE_STACK map types 523 // implement this command as a "pop" operation, deleting the top 524 // element rather than one corresponding to attr.Key. 525 // The attr.Key parameter should be zeroed when issuing this operation for these map types. 526 // 527 // This command is only valid for the following map types: 528 // * bpftypes.BPF_MAP_TYPE_QUEUE 529 // * bpftypes.BPF_MAP_TYPE_STACK 530 func MapLookupAndDeleteElement(attr *BPFAttrMapElem) error { 531 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapLookupAndDelete) { 532 return fmt.Errorf("map lookup and delete element not supported: %w", ErrNotSupported) 533 } 534 535 return bpfNoReturn(bpftypes.BPF_MAP_LOOKUP_AND_DELETE_ELEM, attr, int(attr.Size())) 536 } 537 538 // MapFreeze freezes the permissions of the specified map. 539 // 540 // Write permissions may be frozen by passing zero attr.Flags. 541 // Upon success, no future syscall invocations may alter the 542 // map state of attr.MapFD. Write operations from eBPF programs 543 // are still possible for a frozen map. 544 // 545 // Not supported for maps of type bpftypes.BPF_MAP_TYPE_STRUCT_OPS. 546 func MapFreeze(attr *BPFAttrMapElem) error { 547 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapFreeze) { 548 return fmt.Errorf("map freeze not supported: %w", ErrNotSupported) 549 } 550 551 return bpfNoReturn(bpftypes.BPF_MAP_FREEZE, attr, int(attr.Size())) 552 } 553 554 // BTFGetNextID fetches the next BPF Type Format (BTF) object currently loaded into the kernel. 555 // 556 // Looks for the BTF object with an id greater than attr.ID and updates attr.NextID on success. 557 // If no other BTF objects remain with ids higher than attr.ID, an error with errno ENOENT(2) is returned. 558 func BTFGetNextID(attr *BPFAttrGetID) error { 559 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIBTFGetNextID) { 560 return fmt.Errorf("BTF next ID not supported: %w", ErrNotSupported) 561 } 562 563 return bpfNoReturn(bpftypes.BPF_BTF_GET_NEXT_ID, attr, int(attr.Size())) 564 } 565 566 // MapLookupBatch iterates and fetches multiple elements in a map. 567 // 568 // Two opaque values are used to manage batch operations, 569 // attr.InBatch and attr.OutBatch. Initially, attr.InBatch must be set 570 // to NULL to begin the batched operation. After each subsequent 571 // MapLookupBatch, the caller should pass the resultant 572 // attr.OutBatch as the attr.InBatch for the next operation to 573 // continue iteration from the current point. 574 // 575 // The attr.Keys and attr.Values are output parameters which must point 576 // to memory large enough to hold attr.Count items based on the key 577 // and value size of the map attr.MapFD. The attr.Keys buffer must be 578 // of sizeof(key_type) * attr.Count. The attr.Values buffer must be of 579 // sizeof(value_type) * attr.Count. 580 // 581 // The attr.ElemFlags argument may be specified as one of the 582 // following: 583 // 584 // BPFMapElemLock 585 // Look up the value of a spin-locked map without 586 // returning the lock. This must be specified if the 587 // elements contain a spinlock. 588 // 589 // On success, attr.Count elements from the map are copied into the 590 // user buffer, with the keys copied into attr.Keys and the values 591 // copied into the corresponding indices in attr.Values. 592 // 593 // If an error is returned and errno is not unix.EFAULT, attr.Count 594 // is set to the number of successfully processed elements. 595 func MapLookupBatch(attr *BPFAttrMapBatch) error { 596 // If the user attempts to use a unsupported feature, tell them to avoid unexpected behavior 597 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapBatchOps) { 598 return fmt.Errorf("batch lookup not supported: %w", ErrNotSupported) 599 } 600 601 err := bpfNoReturn(bpftypes.BPF_MAP_LOOKUP_BATCH, attr, int(attr.Size())) 602 if syserr, ok := err.(*BPFSyscallError); ok { 603 syserr.Err = map[unix.Errno]string{ 604 unix.ENOENT: "last batch in the map", 605 }[syserr.Errno] 606 return syserr 607 } 608 return err 609 } 610 611 // MapLookupBatchAndDelete iterates and delete all elements in a map. 612 // This operation has the same behavior as 613 // MapLookupBatch with two exceptions: 614 // * Every element that is successfully returned is also deleted 615 // from the map. This is at least attr.Count elements. Note that 616 // attr.Count is both an input and an output parameter. 617 // * Upon returning with errno set to unix.EFAULT, up to 618 // attr.Count elements may be deleted without returning the keys 619 // and values of the deleted elements. 620 func MapLookupBatchAndDelete(attr *BPFAttrMapBatch) error { 621 // If the user attempts to use a unsupported feature, tell them to avoid unexpected behavior 622 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapBatchOps) { 623 return fmt.Errorf("batch lookup and delete not supported: %w", ErrNotSupported) 624 } 625 626 return bpfNoReturn(bpftypes.BPF_MAP_LOOKUP_AND_DELETE_BATCH, attr, int(attr.Size())) 627 } 628 629 // MapUpdateBatch updates multiple elements in a map by *key*. 630 // 631 // The attr.Keys and attr.Value are input parameters which must point 632 // to memory large enough to hold attr.Count items based on the key 633 // and value size of the map attr.MapFD. The attr.Keys buffer must be 634 // of sizeof(key_type) * attr.Count. The attr.Values buffer must be of 635 // sizeof(value_type) * attr.Count. 636 // 637 // Each element specified in attr.Keys is sequentially updated to the 638 // value in the corresponding index in attr.Values. The attr.InBatch 639 // and attr.OutBatch parameters are ignored and should be zeroed. 640 // 641 // The attr.ElemFlags argument should be specified as one of the 642 // following: 643 // 644 // BPFMapElemAny 645 // Create new elements or update a existing elements. 646 // BPFMapElemNoExists 647 // Create new elements only if they do not exist. 648 // BPFMapElemExists 649 // Update existing elements. 650 // BPFMapElemLock 651 // Update spin_lock-ed map elements. This must be 652 // specified if the map value contains a spinlock. 653 // 654 // On success, attr.Count elements from the map are updated. 655 // 656 // If an error is returned and errno is not unix.EFAULT, attr.Count 657 // is set to the number of successfully processed elements. 658 func MapUpdateBatch(attr *BPFAttrMapBatch) error { 659 // If the user attempts to use a unsupported feature, tell them to avoid unexpected behavior 660 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapBatchOps) { 661 return fmt.Errorf("batch update not supported: %w", ErrNotSupported) 662 } 663 664 err := bpfNoReturn(bpftypes.BPF_MAP_UPDATE_BATCH, attr, int(attr.Size())) 665 if syserr, ok := err.(*BPFSyscallError); ok { 666 syserr.Err = map[unix.Errno]string{ 667 unix.E2BIG: "the number of elements in the map reached the *max_entries* limit specified at map " + 668 "creation time", 669 unix.EEXIST: "attr.Flags specifies BPFMapElemNoExists and the element with attr.Keys[*] already " + 670 "exists in the map", 671 unix.ENOENT: "attr.Flags specifies BPFMapElemExists and the element with attr.Keys[*] does not " + 672 "exist in the map", 673 }[syserr.Errno] 674 return syserr 675 } 676 677 return err 678 } 679 680 // MapDeleteBatch deletes multiple elements in a map. 681 // 682 // The attr.Keys parameter is an input parameter which must point 683 // to memory large enough to hold attr.Count items based on the key 684 // size of the map attr.MapFD, that is, sizeof(key_type) * attr.Count. 685 // 686 // Each element specified in attr.Keys is sequentially deleted. The 687 // attr.InBatch, attr.OutBatch, and attr.Values parameters are ignored 688 // and should be zeroed. 689 // 690 // The attr.ElemFlags argument may be specified as one of the 691 // following: 692 // 693 // BPFMapElemLock 694 // Look up the value of a spin-locked map without 695 // returning the lock. This must be specified if the 696 // elements contain a spinlock. 697 // 698 // On success, attr.Count elements from the map are updated. 699 // 700 // If an error is returned and errno is not unix.EFAULT, attr.Count 701 // is set to the number of successfully processed elements. If 702 // errno is unix.EFAULT, up to attr.Count elements may be been 703 // deleted. 704 func MapDeleteBatch(attr *BPFAttrMapBatch) error { 705 // If the user attempts to use a unsupported feature, tell them to avoid unexpected behavior 706 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIMapBatchOps) { 707 return fmt.Errorf("batch lookup and delete not supported: %w", ErrNotSupported) 708 } 709 710 return bpfNoReturn(bpftypes.BPF_MAP_DELETE_BATCH, attr, int(attr.Size())) 711 } 712 713 // LinkCreate attaches an eBPF program to a attr.TargetFD at the specified 714 // attr.AttachType hook and return a file descriptor handle for 715 // managing the link. 716 func LinkCreate(attr *BPFAttrLinkCreate) (fd BPFfd, err error) { 717 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPILinkCreate) { 718 return 0, fmt.Errorf("link create not supported: %w", ErrNotSupported) 719 } 720 721 return Bpf(bpftypes.BPF_LINK_CREATE, attr, int(attr.Size())) 722 } 723 724 // LinkUpdate updates the eBPF program in the specified attr.LinkFD to attr.NewProgFD. 725 func LinkUpdate(attr *BPFAttrLinkUpdate) error { 726 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPILinkUpdate) { 727 return fmt.Errorf("link update not supported: %w", ErrNotSupported) 728 } 729 730 return bpfNoReturn(bpftypes.BPF_LINK_UPDATE, attr, int(attr.Size())) 731 } 732 733 // LinkGetFDByID opens a file descriptor for the eBPF Link corresponding to attr.LinkID 734 func LinkGetFDByID(attr *BPFAttrGetID) (fd BPFfd, err error) { 735 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPILinkGetFDByID) { 736 return 0, fmt.Errorf("link get fd by id not supported: %w", ErrNotSupported) 737 } 738 739 return Bpf(bpftypes.BPF_LINK_GET_FD_BY_ID, attr, int(attr.Size())) 740 } 741 742 // LinkGetNextID fetches the next eBPF program currently loaded into the kernel. 743 // Looks for the eBPF link with an id greater than attr.ID and updates attr.NextID on success. 744 // If no other eBPF links remain with ids higher than attr.ID, an error with errno ENOENT(2) is returned. 745 func LinkGetNextID(attr *BPFAttrGetID) error { 746 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPILinkGetNextID) { 747 return fmt.Errorf("link get next id not supported: %w", ErrNotSupported) 748 } 749 750 return bpfNoReturn(bpftypes.BPF_LINK_GET_NEXT_ID, attr, int(attr.Size())) 751 } 752 753 // EnableStats enables eBPF runtime statistics gathering. 754 // Runtime statistics gathering for the eBPF runtime is disabled 755 // by default to minimize the corresponding performance overhead. 756 // This command enables statistics globally. 757 // 758 // Multiple programs may independently enable statistics. 759 // After gathering the desired statistics, eBPF runtime statistics 760 // may be disabled again by calling Close() for the file 761 // descriptor returned by this function. Statistics will only be 762 // disabled system-wide when all outstanding file descriptors 763 // returned by prior calls for this subcommand are closed. 764 func EnableStats(attr *BPFAttrEnableStats) (fd BPFfd, err error) { 765 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIEnableStats) { 766 return 0, fmt.Errorf("enable stats not supported: %w", ErrNotSupported) 767 } 768 769 return Bpf(bpftypes.BPF_ENABLE_STATS, attr, int(attr.Size())) 770 } 771 772 // IterCreate creates an iterator on top of the specified attr.LinkFD (as 773 // previously created using LinkUpdate) and return a 774 // file descriptor that can be used to trigger the iteration. 775 // 776 // If the resulting file descriptor is pinned to the filesystem 777 // using ObjectPin, then subsequent unix.Read syscalls 778 // for that path will trigger the iterator to read kernel state 779 // using the eBPF program attached to attr.LinkFD. 780 func IterCreate(attr *BPFAttrIterCreate) (fd BPFfd, err error) { 781 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIIterCreate) { 782 return 0, fmt.Errorf("iter create not supported: %w", ErrNotSupported) 783 } 784 785 return Bpf(bpftypes.BPF_ITER_CREATE, attr, int(attr.Size())) 786 } 787 788 // LinkDetach forcefully detaches the specified attr.LinkFD from its 789 // corresponding attachment point. 790 func LinkDetach(attr *BPFAttrLinkDetach) error { 791 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPILinkDetach) { 792 return fmt.Errorf("link detach not supported: %w", ErrNotSupported) 793 } 794 795 return bpfNoReturn(bpftypes.BPF_LINK_DETACH, attr, int(attr.Size())) 796 } 797 798 // ProgBindMap Bind a map to the lifetime of an eBPF program. 799 // 800 // The map identified by attr.MapFD is bound to the program 801 // identified by attr.ProgFD and only released when attr.ProgFD is 802 // released. This may be used in cases where metadata should be 803 // associated with a program which otherwise does not contain any 804 // references to the map (for example, embedded in the eBPF 805 // program instructions). 806 func ProgBindMap(attr *BPFAttrProgBindMap) error { 807 if !kernelsupport.CurrentFeatures.API.Has(kernelsupport.KFeatAPIProgBindMap) { 808 return fmt.Errorf("prog bind map not supported: %w", ErrNotSupported) 809 } 810 811 return bpfNoReturn(bpftypes.BPF_PROG_BIND_MAP, attr, int(attr.Size())) 812 }