github.com/jayanthvn/pure-gobpf@v0.0.0-20230623131354-8d1d959d9e0b/pkg/utils/utils.go (about)

     1  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License").
     4  // You may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  //limitations under the License.
    14  
    15  package utils
    16  
    17  import (
    18  	"encoding/binary"
    19  	"fmt"
    20  	"os"
    21  	"runtime"
    22  	"unsafe"
    23  
    24  	"github.com/jayanthvn/pure-gobpf/pkg/logger"
    25  	"golang.org/x/sys/unix"
    26  )
    27  
    28  const (
    29  	// BPF map type constants. Must match enum bpf_map_type from linux/bpf.h
    30  	BPF_MAP_TYPE_UNSPEC           = 0
    31  	BPF_MAP_TYPE_HASH             = 1
    32  	BPF_MAP_TYPE_ARRAY            = 2
    33  	BPF_MAP_TYPE_PROG_ARRAY       = 3
    34  	BPF_MAP_TYPE_PERF_EVENT_ARRAY = 4
    35  	BPF_MAP_TYPE_PERCPU_HASH      = 5
    36  	BPF_MAP_TYPE_PERCPU_ARRAY     = 6
    37  	BPF_MAP_TYPE_STACK_TRACE      = 7
    38  	BPF_MAP_TYPE_CGROUP_ARRAY     = 8
    39  	BPF_MAP_TYPE_LRU_HASH         = 9
    40  	BPF_MAP_TYPE_LRU_PERCPU_HASH  = 10
    41  	BPF_MAP_TYPE_LPM_TRIE         = 11
    42  	BPF_MAP_TYPE_ARRAY_OF_MAPS    = 12
    43  	BPF_MAP_TYPE_HASH_OF_MAPS     = 13
    44  	BPF_MAP_TYPE_DEVMAP           = 14
    45  
    46  	// BPF syscall command constants. Must match enum bpf_cmd from linux/bpf.h
    47  	BPF_MAP_CREATE         = 0
    48  	BPF_MAP_LOOKUP_ELEM    = 1
    49  	BPF_MAP_UPDATE_ELEM    = 2
    50  	BPF_MAP_DELETE_ELEM    = 3
    51  	BPF_MAP_GET_NEXT_KEY   = 4
    52  	BPF_PROG_LOAD          = 5
    53  	BPF_OBJ_PIN            = 6
    54  	BPF_OBJ_GET            = 7
    55  	BPF_PROG_ATTACH        = 8
    56  	BPF_PROG_DETACH        = 9
    57  	BPF_PROG_TEST_RUN      = 10
    58  	BPF_PROG_GET_NEXT_ID   = 11
    59  	BPF_MAP_GET_NEXT_ID    = 12
    60  	BPF_PROG_GET_FD_BY_ID  = 13
    61  	BPF_MAP_GET_FD_BY_ID   = 14
    62  	BPF_OBJ_GET_INFO_BY_FD = 15
    63  
    64  	// Flags for BPF_MAP_UPDATE_ELEM. Must match values from linux/bpf.h
    65  	BPF_ANY     = 0
    66  	BPF_NOEXIST = 1
    67  	BPF_EXIST   = 2
    68  
    69  	BPF_F_NO_PREALLOC   = 1 << 0
    70  	BPF_F_NO_COMMON_LRU = 1 << 1
    71  
    72  	// BPF MAP pinning
    73  	PIN_NONE      = 0
    74  	PIN_OBJECT_NS = 1
    75  	PIN_GLOBAL_NS = 2
    76  	PIN_CUSTOM_NS = 3
    77  
    78  	BPF_DIR_MNT     = "/sys/fs/bpf/"
    79  	BPF_DIR_GLOBALS = "globals"
    80  	BPF_FS_MAGIC    = 0xcafe4a11
    81  
    82  	BPFObjNameLen    = 16
    83  	BPFProgInfoAlign = 8
    84  	BPFTagSize       = 8
    85  
    86  	/*
    87  	 * C struct of bpf_ins is 8 bytes because of this -
    88  	 * struct bpf_insn {
    89  	 *	__u8	code;
    90  	 * 	__u8	dst_reg:4;
    91  	 *	__u8	src_reg:4;
    92  	 * 	__s16	off;
    93  	 * 	__s32	imm;
    94  	 *	};
    95  	 * while go struct will return 9 since we dont have bit fields hence we dec(1).
    96  	 */
    97  	PROG_BPF_FS = "/sys/fs/bpf/globals/aws/programs/"
    98  	MAP_BPF_FS  = "/sys/fs/bpf/globals/aws/maps/"
    99  )
   100  
   101  type BPFInsn struct {
   102  	Code   uint8 // Opcode
   103  	DstReg uint8 // 4 bits: destination register, r0-r10
   104  	SrcReg uint8 // 4 bits: source register, r0-r10
   105  	Off    int16 // Signed offset
   106  	Imm    int32 // Immediate constant
   107  }
   108  
   109  type BpfPin struct {
   110  	Pathname  uintptr
   111  	Fd        uint32
   112  	FileFlags uint32
   113  }
   114  
   115  type BpfMapAttr struct {
   116  	MapFD uint32
   117  	pad0  [4]byte
   118  	Key   uint64
   119  	Value uint64 // union: value or next_key
   120  	Flags uint64
   121  }
   122  
   123  func PinObject(objFD uint32, pinPath string) error {
   124  	var log = logger.Get()
   125  
   126  	if pinPath == "" {
   127  		return nil
   128  	}
   129  	cPath := []byte(pinPath + "\x00")
   130  
   131  	pinAttr := BpfPin{
   132  		Fd:       uint32(objFD),
   133  		Pathname: uintptr(unsafe.Pointer(&cPath[0])),
   134  	}
   135  	pinData := unsafe.Pointer(&pinAttr)
   136  	pinDataSize := unsafe.Sizeof(pinAttr)
   137  
   138  	log.Infof("Calling BPFsys for FD %d and Path %s", objFD, pinPath)
   139  
   140  	ret, _, errno := unix.Syscall(
   141  		unix.SYS_BPF,
   142  		uintptr(BPF_OBJ_PIN),
   143  		uintptr(pinData),
   144  		uintptr(int(pinDataSize)),
   145  	)
   146  	if errno < 0 {
   147  		log.Infof("Unable to pin map and ret %d and err %s", int(ret), errno)
   148  		return fmt.Errorf("Unable to pin map: %s", errno)
   149  	}
   150  	//TODO : might have to return FD for node agent
   151  	log.Infof("Pin done with fd : %d and errno %d", ret, errno)
   152  	return nil
   153  }
   154  
   155  func IsfileExists(fname string) bool {
   156  	info, err := os.Stat(fname)
   157  	if os.IsNotExist(err) {
   158  		return false
   159  	}
   160  	return !info.IsDir()
   161  }
   162  
   163  func UnPinObject(pinPath string) error {
   164  	var log = logger.Get()
   165  	if pinPath == "" || !IsfileExists(pinPath) {
   166  		log.Infof("PinPath is empty or file doesn't exist")
   167  		return nil
   168  	}
   169  
   170  	err := os.Remove(pinPath)
   171  	if err != nil {
   172  		log.Infof("File remove failed ", pinPath)
   173  		return err
   174  	}
   175  
   176  	return err
   177  }
   178  
   179  /*
   180   *
   181   *	struct { anonymous struct used by BPF_*_GET_*_ID
   182   *		union {
   183   *			__u32		start_id;
   184   *			__u32		prog_id;
   185   *			__u32		map_id;
   186   *			__u32		btf_id;
   187   *			__u32		link_id;
   188   *		};
   189   *		__u32		next_id;
   190   *		__u32		open_flags;
   191   *	};
   192   */
   193  
   194  type BpfShowAttr struct {
   195  	id         uint32
   196  	next_id    uint32
   197  	open_flags uint32
   198  }
   199  
   200  func GetMapFDFromID(mapID int) (int, error) {
   201  	var log = logger.Get()
   202  	attr := BpfShowAttr{
   203  		id: uint32(mapID),
   204  	}
   205  	ret, _, errno := unix.Syscall(
   206  		unix.SYS_BPF,
   207  		BPF_MAP_GET_FD_BY_ID,
   208  		uintptr(unsafe.Pointer(&attr)),
   209  		unsafe.Sizeof(attr),
   210  	)
   211  	if errno != 0 {
   212  		log.Infof("Failed to get Map FD - ret %d and err %s", int(ret), errno)
   213  		return 0, errno
   214  	}
   215  	fd := int(ret)
   216  	runtime.KeepAlive(fd)
   217  	return fd, nil
   218  }
   219  
   220  func GetProgFDFromID(mapID int) (int, error) {
   221  	var log = logger.Get()
   222  	attr := BpfShowAttr{
   223  		id: uint32(mapID),
   224  	}
   225  	ret, _, errno := unix.Syscall(
   226  		unix.SYS_BPF,
   227  		BPF_PROG_GET_FD_BY_ID,
   228  		uintptr(unsafe.Pointer(&attr)),
   229  		unsafe.Sizeof(attr),
   230  	)
   231  	if errno != 0 {
   232  		log.Infof("Failed to get Map FD - ret %d and err %s", int(ret), errno)
   233  		return 0, errno
   234  	}
   235  	fd := int(ret)
   236  	runtime.KeepAlive(fd)
   237  	return fd, nil
   238  }
   239  
   240  // Converts BPF instruction into bytes
   241  func (b *BPFInsn) ConvertBPFInstructionToByteStream() []byte {
   242  	res := make([]byte, 8)
   243  	res[0] = b.Code
   244  	res[1] = (b.SrcReg << 4) | (b.DstReg & 0x0f)
   245  	binary.LittleEndian.PutUint16(res[2:], uint16(b.Off))
   246  	binary.LittleEndian.PutUint32(res[4:], uint32(b.Imm))
   247  
   248  	return res
   249  }