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  }