pkg/utils/utils.go (158 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
//limitations under the License.
package utils
import (
"encoding/binary"
"errors"
"fmt"
"io/fs"
"math"
"os"
"runtime"
"syscall"
"unsafe"
constdef "github.com/aws/aws-ebpf-sdk-go/pkg/constants"
"github.com/aws/aws-ebpf-sdk-go/pkg/logger"
"golang.org/x/sys/unix"
)
type BPFInsn struct {
Code uint8 // Opcode
DstReg uint8 // 4 bits: destination register, r0-r10
SrcReg uint8 // 4 bits: source register, r0-r10
Off int16 // Signed offset
Imm int32 // Immediate constant
}
type BpfPin struct {
Pathname uintptr
Fd uint32
FileFlags uint32
}
type BpfMapAttr struct {
MapFD uint32
_ [4]byte
Key uint64
Value uint64 // union: value or next_key
Flags uint64
}
func PinObject(objFD uint32, pinPath string) error {
var log = logger.Get()
if pinPath == "" {
return nil
}
cPath := []byte(pinPath + "\x00")
pinAttr := BpfPin{
Fd: uint32(objFD),
Pathname: uintptr(unsafe.Pointer(&cPath[0])),
}
pinData := unsafe.Pointer(&pinAttr)
pinDataSize := unsafe.Sizeof(pinAttr)
log.Infof("Calling BPFsys for FD %d and Path %s", objFD, pinPath)
ret, _, errno := unix.Syscall(
unix.SYS_BPF,
uintptr(constdef.BPF_OBJ_PIN),
uintptr(pinData),
uintptr(int(pinDataSize)),
)
if errno < 0 {
log.Infof("Unable to pin map and ret %d and err %s", int(ret), errno)
return fmt.Errorf("Unable to pin map: %s", errno)
}
//TODO : might have to return FD for node agent
log.Infof("Pin done with fd : %d and errno %d", ret, errno)
return nil
}
func IsfileExists(fname string) (bool, error) {
info, err := os.Stat(fname)
switch {
case errors.Is(err, fs.ErrNotExist):
return false, nil
case err != nil:
return false, fmt.Errorf("unexpected error stat %q: %w", fname, err)
default:
return !info.IsDir(), nil
}
}
func UnPinObject(pinPath string) error {
var log = logger.Get()
found, err := IsfileExists(pinPath)
if err != nil {
return fmt.Errorf("unable to check file: %w", err)
}
if pinPath == "" || !found {
log.Infof("PinPath is empty or file doesn't exist")
return nil
}
err = os.Remove(pinPath)
if err != nil {
log.Infof("File remove failed ", pinPath)
return err
}
return err
}
/*
*
* struct { anonymous struct used by BPF_*_GET_*_ID
* union {
* __u32 start_id;
* __u32 prog_id;
* __u32 map_id;
* __u32 btf_id;
* __u32 link_id;
* };
* __u32 next_id;
* __u32 open_flags;
* };
*/
type BpfShowAttr struct {
id uint32
next_id uint32
open_flags uint32
}
func GetMapFDFromID(mapID int) (int, error) {
var log = logger.Get()
attr := BpfShowAttr{
id: uint32(mapID),
}
ret, _, errno := unix.Syscall(
unix.SYS_BPF,
uintptr(constdef.BPF_MAP_GET_FD_BY_ID),
uintptr(unsafe.Pointer(&attr)),
unsafe.Sizeof(attr),
)
if errno != 0 {
log.Infof("Failed to get Map FD - ret %d and err %s", int(ret), errno)
return 0, errno
}
fd := int(ret)
runtime.KeepAlive(fd)
return fd, nil
}
func GetProgFDFromID(mapID int) (int, error) {
var log = logger.Get()
attr := BpfShowAttr{
id: uint32(mapID),
}
ret, _, errno := unix.Syscall(
unix.SYS_BPF,
uintptr(constdef.BPF_PROG_GET_FD_BY_ID),
uintptr(unsafe.Pointer(&attr)),
unsafe.Sizeof(attr),
)
if errno != 0 {
log.Infof("Failed to get Map FD - ret %d and err %s", int(ret), errno)
return 0, errno
}
fd := int(ret)
runtime.KeepAlive(fd)
return fd, nil
}
// Converts BPF instruction into bytes
func (b *BPFInsn) ConvertBPFInstructionToByteStream() []byte {
res := make([]byte, 8)
res[0] = b.Code
res[1] = (b.SrcReg << 4) | (b.DstReg & 0x0f)
binary.LittleEndian.PutUint16(res[2:], uint16(b.Off))
binary.LittleEndian.PutUint32(res[4:], uint32(b.Imm))
return res
}
func Mount_bpf_fs() error {
fmt.Println("Let's mount BPF FS")
err := syscall.Mount("bpf", "/sys/fs/bpf", "bpf", 0, "mode=0700")
if err != nil {
fmt.Println("error mounting bpffs")
}
return err
}
func Unmount_bpf_fs() error {
fmt.Println("Let's unmount BPF FS")
err := syscall.Unmount("/sys/fs/bpf", 0)
if err != nil {
fmt.Println("error unmounting bpffs")
}
return err
}
func GetLogBufferSize() int {
return math.MaxUint32 >> 8
}