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 }