Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Makefile: improvements #28

Merged
merged 9 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
selftest/dist
output*
selftest/*/main
selftest/*/*.o
selftest/*/*-static
selftest/*/*-dynamic
selftest/uprobe/ctest
selftest/uprobe/gotest
7 changes: 3 additions & 4 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

[submodule "selftest/libbpf-module"]
path = selftest/libbpf-module
url = https://github.com/libbpf/libbpf
[submodule "libbpf"]
path = libbpf
url = https://github.com/libbpf/libbpf.git
176 changes: 154 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,29 +1,161 @@
TARGET_BPF := test/test.bpf.o
VMLINUX_H = test/vmlinux.h
BASEDIR = $(abspath ./)

GO_SRC := $(shell find . -type f -name '*.go')
BPF_SRC := $(shell find . -type f -name '*.bpf.c')
PWD := $(shell pwd)
OUTPUT = ./output
SELFTEST = ./selftest

LIBBPF_HEADERS := /usr/include/bpf
LIBBPF := "-lbpf"
CC = gcc
CLANG = clang

.PHONY: all
all: test
ARCH := $(shell uname -m)
ARCH := $(subst x86_64,amd64,$(ARCH))

$(VMLINUX_H):
bpftool btf dump file /sys/kernel/btf/vmlinux format c > test/vmlinux.h
BTFFILE = /sys/kernel/btf/vmlinux
BPFTOOL = $(shell which bpftool || /bin/false)
VMLINUXH = $(OUTPUT)/vmlinux.h

go_env := CC=gcc CGO_CFLAGS="-I $(LIBBPF_HEADERS)" CGO_LDFLAGS="$(LIBBPF)"
.PHONY: test
test: $(TARGET_BPF) $(GO_SRC)
$(go_env) go test -ldflags '-extldflags "-static"' .
# libbpf

$(TARGET_BPF): $(BPF_SRC) $(VMLINUX_H)
clang \
-g -O2 -c -target bpf \
-o $@ $<
LIBBPF_SRC = $(abspath ./libbpf/src)
LIBBPF_OBJ = $(abspath ./$(OUTPUT)/libbpf.a)
LIBBPF_OBJDIR = $(abspath ./$(OUTPUT)/libbpf)
LIBBPF_DESTDIR = $(abspath ./$(OUTPUT))

.PHONY: clean
clean:
rm $(TARGET_BPF) $(VMLINUX_H)
CFLAGS = -g -O2 -Wall -fpie
LDFLAGS =

# golang

CGO_CFLAGS_STATIC = "-I$(abspath $(OUTPUT))"
CGO_LDFLAGS_STATIC = "-lelf -lz $(LIBBPF_OBJ)"
CGO_EXTLDFLAGS_STATIC = '-w -extldflags "-static"'

CGO_CFGLAGS_DYN = "-I. -I/usr/include/"
CGO_LDFLAGS_DYN = "-lelf -lz -lbpf"

# default == shared lib from OS package

all: libbpfgo-dynamic
test: libbpfgo-dynamic-test

# libbpfgo test object

libbpfgo-test-bpf-static: libbpfgo-static # needed for serialization
$(MAKE) -C $(SELFTEST)/build

libbpfgo-test-bpf-dynamic: libbpfgo-dynamic # needed for serialization
$(MAKE) -C $(SELFTEST)/build

libbpfgo-test-bpf-clean:
$(MAKE) -C $(SELFTEST)/build clean

# libbpf: shared

libbpfgo-dynamic: $(OUTPUT)/libbpf
CC=$(CLANG) \
CGO_CFLAGS=$(CGO_CFLAGS_DYN) \
CGO_LDFLAGS=$(CGO_LDFLAGS_DYN) \
go build .

libbpfgo-dynamic-test: libbpfgo-test-bpf-dynamic
CC=$(CLANG) \
CGO_CFLAGS=$(CGO_CFLAGS_DYN) \
CGO_LDFLAGS=$(CGO_LDFLAGS_DYN) \
sudo -E go test .

# libbpf: static

libbpfgo-static: $(VMLINUXH) | $(LIBBPF_OBJ)
CC=$(CLANG) \
CGO_CFLAGS=$(CGO_CFLAGS_STATIC) \
CGO_LDFLAGS=$(CGO_LDFLAGS_STATIC) \
GOOS=linux GOARCH=$(ARCH) \
go build \
-tags netgo -ldflags $(CGO_EXTLDFLAGS_STATIC) \
.

libbpfgo-static-test: libbpfgo-test-bpf-static
CC=$(CLANG) \
CGO_CFLAGS=$(CGO_CFLAGS_STATIC) \
CGO_LDFLAGS=$(CGO_LDFLAGS_STATIC) \
GOOS=linux GOARCH=$(ARCH) \
sudo -E -- go test \
-tags netgo -ldflags $(CGO_EXTLDFLAGS_STATIC) \
.

# vmlinux header file

.PHONY: vmlinuxh
vmlinuxh: $(VMLINUXH)

$(VMLINUXH): $(OUTPUT)
@if [ ! -f $(BTFFILE) ]; then \
echo "ERROR: kernel does not seem to support BTF"; \
exit 1; \
fi
@if [ ! -f $(VMLINUXH) ]; then \
echo "INFO: generating $(VMLINUXH) from $(BTFFILE)"; \
$(BPFTOOL) btf dump file $(BTFFILE) format c > $(VMLINUXH); \
fi

# static libbpf generation for the git submodule

$(LIBBPF_OBJ): $(wildcard $(LIBBPF_SRC)/*.[ch]) | $(OUTPUT)/libbpf
CC="$(CC)" CFLAGS="$(CFLAGS)" LD_FLAGS="$(LDFLAGS)" \
$(MAKE) -C $(LIBBPF_SRC) \
BUILD_STATIC_ONLY=1 \
OBJDIR=$(LIBBPF_OBJDIR) \
DESTDIR=$(LIBBPF_DESTDIR) \
INCLUDEDIR= LIBDIR= UAPIDIR= install

# selftests

SELFTESTS = $(shell find $(SELFTEST) -mindepth 1 -maxdepth 1 -type d ! -name 'common' ! -name 'build')

define FOREACH
SELFTESTERR=0; \
for DIR in $(SELFTESTS); do \
echo "INFO: entering $$DIR..."; \
$(MAKE) -j8 -C $$DIR $(1) || SELFTESTERR=1; \
done; \
if [ $$SELFTESTERR -eq 1 ]; then \
exit 1; \
fi
endef

.PHONY: selftest
.PHONY: selftest-static
.PHONY: selftest-dynamic
.PHONY: selftest-run
.PHONY: selftest-static-run
.PHONY: selftest-dynamic-run
.PHONY: selftest-clean

selftest: selftest-static

selftest-static:
$(call FOREACH, main-static)
selftest-dynamic:
$(call FOREACH, main-dynamic)

selftest-run: selftest-static-run

selftest-static-run:
$(call FOREACH, run-static)
selftest-dynamic-run:
$(call FOREACH, run-dynamic)

selftest-clean:
$(call FOREACH, clean)

# output

$(OUTPUT):
mkdir -p $(OUTPUT)

$(OUTPUT)/libbpf:
mkdir -p $(OUTPUT)/libbpf

# cleanup

clean: selftest-clean libbpfgo-test-bpf-clean
rafaeldtinoco marked this conversation as resolved.
Show resolved Hide resolved
rm -rf $(OUTPUT)
69 changes: 54 additions & 15 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,61 @@

rafaeldtinoco marked this conversation as resolved.
Show resolved Hide resolved
<img src="docs/images/aqua-tux.png" width="150" height="auto">

___
----

libbpfgo is a Go library for working with Linux's [eBPF](https://ebpf.io/). It was created for [Tracee](https://github.com/aquasecurity/tracee), our open source Runtime Security and eBPF tracing tools written in Go. If you are interested in eBPF and it's applications, check out Tracee on Github: [https://github.com/aquasecurity/tracee](https://github.com/aquasecurity/tracee).
libbpfgo is a Go library for Linux's [eBPF](https://ebpf.io/) project. It was created for [Tracee](https://github.com/aquasecurity/tracee), our open source Runtime Security, and eBPF tracing tool, written in Go. If you are interested in eBPF and its applications, check out Tracee at Github: [https://github.com/aquasecurity/tracee](https://github.com/aquasecurity/tracee).

libbpfgo is built around libbpf - the standard library for interacting with eBPF from userspace, which is a C library maintained in Linux upstream. We have created libbpfgo as a thin Go wrapper around libbpf.
libbpfgo is built around [libbpf](https://github.com/libbpf/libbpf) - the standard library for interacting with eBPF programs from userspace - which is a C library maintained in Linux upstream. We have created libbpfgo as a thin Go wrapper around the libbpf project.

## Installing

libbpfgo is using CGO to interop with libbpf and will expect to be linked with libbpf at run or link time. Simply importing libbpfgo is not enough to get started, and you will need to fulfill the required dependency in one of the following ways:
libbpfgo uses CGO to interop with libbpf and will expect to be linked with libbpf at run or link time. Simply importing libbpfgo is not enough to get started, and you will need to fulfill the required dependency in one of the following ways:

1. Install the libbpf as a shared object in the system. Libbpf may already be packaged for you distribution, if not, you can build and install from source. More info [here](https://github.com/libbpf/libbpf).
1. Embed libbpf into your Go project as a vendored dependency. This means that the libbpf code is statically linked into the resulting binary, and there are no runtime dependencies. [Tracee](https://github.com/aquasecurity/tracee) takes this approach and you can take example from it's [Makefile](https://github.com/aquasecurity/tracee/blob/f8df7da6a27f729610992b6bd52e89d510fcf384/tracee-ebpf/Makefile#L62).
1. Install libbpf as a shared object in the system. Libbpf may already be packaged for your distribution and, if not, you can build and install from source. More info [here](https://github.com/libbpf/libbpf).
1. Embed libbpf into your Go project as a vendored dependency. This means that the libbpf code is statically linked into the resulting binary, and there are no runtime dependencies. [Tracee](https://github.com/aquasecurity/tracee) takes this approach.

In the next sesssion you will find different ways to build libbpfgo.

## Building

Currently you will find the following GNU Makefile rules:

| Makefile Rule | Description |
|--------------------------|-----------------------------------|
| all | builds libbpfgo (dynamic) |
| clean | cleans entire tree |
| selftest | builds all selftests (static) |
| selftest-run | runs all selftests (static) |

* libbpf dynamically linked (libbpf from OS)

| Makefile Rule | Description |
|--------------------------|-----------------------------------|
| libbpfgo-dynamic | builds dynamic libbpfgo (libbpf) |
| libbpfgo-dynamic-test | 'go test' with dynamic libbpfgo |
| selftest-dynamic | build tests with dynamic libbpfgo |
| selftest-dynamic-run | run tests using dynamic libbpfgo |

* statically compiled (libbpf submodule)

| Makefile Rule | Description |
|--------------------------|-----------------------------------|
| libbpfgo-static | builds static libbpfgo (libbpf) |
| libbpfgo-static-test | 'go test' with static libbpfgo |
| selftest-static | build tests with static libbpfgo |
| selftest-static-run | run tests using static libbpfgo |

* examples

```
$ make libbpfgo-static => libbpfgo statically linked with libbpf
$ make -C selftest/perfbuffers => single selftest build (static libbpf)
$ make -C selftest/perfbuffers run-dynamic => single selftest run (dynamic libbpf)
$ make selftest-static-run => will build & run all static selftests
```

> Note 01: dynamic builds need your OS to have a *recent enough* libbpf package (and its headers) installed. Sometimes, recent features might require the use of backported OS packages in order for your OS to contain latest *libbpf* features (sometimes required by libbpfgo).
> Note 02: static builds need `git submodule init` first. Make sure to sync the *libbpf* git submodule before trying to statically compile or test the *libbpfgo* repository.

## Concepts

Expand Down Expand Up @@ -47,15 +90,11 @@ rb.Start()
e := <-eventsChannel
```

Please check our github milestones for an idea of the project roadmap. The general goal is to fully implement/expose libbpf's API in Go as seamlessly as possible.

Please check our github milestones for an idea of the project roadmap. The general goal is to fully implement/expose libbpf's API in Go as seamlessly as possible.

## Learn more

- Blost post on [how to Build eBPF Programs with libbpfgo](https://blog.aquasec.com/libbpf-ebpf-programs)

- The [selftests](./selftest) are small programs that use libbpfgo to verify functionality, they're good examples to look at for usage.

- [tracee-ebpf](https://github.com/aquasecurity/tracee/tree/main/tracee-ebpf) is a robust consumer of this package.

- Feel free to ask questions by creating a new [Discussion](https://github.com/aquasecurity/libbpfgo/discussions) and we'd love to help.
- [How to Build eBPF Programs with libbpfgo](https://blog.aquasec.com/libbpf-ebpf-programs).
- [selftests](./selftest) are small program using libbpfgo and might be good usage examples.
- [tracee-ebpf](https://github.com/aquasecurity/tracee/tree/main/tracee-ebpf) is a robust consumer of this project.
- Feel free to ask questions by creating a new [Discussion](https://github.com/aquasecurity/libbpfgo/discussions), we'd love to help.
4 changes: 2 additions & 2 deletions libbpfgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ func doAttachUprobe(prog *BPFProg, isUretprobe bool, pid int, path string, offse
link := C.bpf_program__attach_uprobe(prog.prog, retCBool, pidCint, pathCString, offsetCsizet)
C.free(unsafe.Pointer(pathCString))
if C.IS_ERR_OR_NULL(unsafe.Pointer(link)) {
return nil, errptrError(unsafe.Pointer(link), "failed to attach u(ret)probe to program %s:%d with pid %s, ", path, offset, pid)
return nil, errptrError(unsafe.Pointer(link), "failed to attach u(ret)probe to program %s:%d with pid %d, ", path, offset, pid)
}

upType := Uprobe
Expand All @@ -813,7 +813,7 @@ func doAttachUprobe(prog *BPFProg, isUretprobe bool, pid int, path string, offse
link: link,
prog: prog,
linkType: upType,
eventName: fmt.Sprintf("%s:%d:%s", path, pid, offset),
eventName: fmt.Sprintf("%s:%d:%d", path, pid, offset),
}
return bpfLink, nil
}
Expand Down
4 changes: 2 additions & 2 deletions libbpfgo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import (

func Test_LoadAndAttach(t *testing.T) {
// load non exisiting file, should fail
module, err := NewModuleFromFile("test/foo.bpf.o")
module, err := NewModuleFromFile("foo.bpf.o")
if err == nil {
t.Errorf("NewModuleFromFile returned nil error on non-existing file")
}

module, err = NewModuleFromFile("test/test.bpf.o")
module, err = NewModuleFromFile("selftest/build/libbpfgo_test.bpf.o")
if err != nil {
t.Fatalf("NewModuleFromFile failed: %v", err)
}
Expand Down
4 changes: 0 additions & 4 deletions selftest/.gitignore

This file was deleted.

32 changes: 32 additions & 0 deletions selftest/build/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
BASEDIR = $(abspath ../../)

OUTPUT = ../../output

CC = gcc
CLANG = clang

CFLAGS = -g -O2 -Wall -fpie
LDFLAGS =

TEST = libbpfgo_test

all: $(TEST).bpf.o

## main tree dependency

outputdir:
$(MAKE) -C $(BASEDIR) outputdir

vmlinuxh: outputdir
$(MAKE) -C $(BASEDIR) vmlinuxh

## test bpf dependency

$(TEST).bpf.o: $(TEST).bpf.c
$(MAKE) -C $(BASEDIR) vmlinuxh
rafaeldtinoco marked this conversation as resolved.
Show resolved Hide resolved
$(CLANG) $(CFLAGS) -target bpf -I$(OUTPUT) -c $< -o $@

## clean

clean:
rm -f *.o
2 changes: 1 addition & 1 deletion test/test.bpf.c → selftest/build/libbpfgo_test.bpf.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//+build ignore
#include "vmlinux.h"
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

Expand Down
Loading