Skip to content
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
100 changes: 100 additions & 0 deletions .github/workflows/generate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: generate

on:
push:
pull_request:
release:
types: [published]

jobs:
generate:
runs-on: ubuntu-latest
container: debian:trixie
steps:
- name: Install toolchain
run: |
apt-get update
apt-get install -y --no-install-recommends ca-certificates git clang llvm libbpf-dev linux-libc-dev
# clang -target bpf does not search the multiarch include dir, so linux/types.h can't find asm/types.h.
ln -sf "/usr/include/$(uname -m)-linux-gnu/asm" /usr/include/asm

- uses: actions/checkout@v5

- uses: actions/setup-go@v6
with:
go-version-file: go.mod

- name: Mark workspace as safe
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

- name: Regenerate BPF objects
run: go generate ./...

- name: Check generated files are up to date
run: |
git diff --exit-code
test -z "$(git status --porcelain)"

- name: Build
run: |
GOARCH=amd64 go build ./...
GOARCH=arm64 go build ./...
GOARCH=s390x go build ./...

- name: Vet
run: go vet ./...

- name: Test
env:
CC: clang
run: go test -race ./...

e2e:
needs: generate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- uses: actions/setup-go@v6
with:
go-version-file: go.mod

- name: Build test binary
run: go test -c -race -o packetdump.test ./packetdump

- name: End-to-end test on lo
run: sudo ./packetdump.test -test.run TestEndToEndLoopback -test.v

release:
if: github.event_name == 'release'
needs: generate
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v5

- uses: actions/setup-go@v6
with:
go-version-file: go.mod

- name: Build binaries
env:
CGO_ENABLED: "0"
GOOS: linux
run: |
mkdir dist
for arch in amd64 arm64 s390x; do
GOARCH=$arch go build -trimpath -ldflags="-s -w" -o "dist/flowexport-linux-$arch" .
GOARCH=$arch go build -trimpath -ldflags="-s -w" -o "dist/packetdump-linux-$arch" ./packetdump/cmd
GOARCH=$arch go build -trimpath -ldflags="-s -w" -o "dist/promexport-linux-$arch" ./promexport/cmd
done

- name: Write checksums
working-directory: dist
run: sha256sum * > SHA256SUMS

- name: Upload release assets
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload "${{ github.event.release.tag_name }}" dist/* --repo "$GITHUB_REPOSITORY" --clobber
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dump
export
*.test
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.17 AS builder
FROM golang:1.25 AS builder
RUN apt-get update

# add local repo into the builder
Expand Down
69 changes: 61 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,70 @@ by using kernel counters such as:
However, the current version just exports packet and byte counts by etype and
protocol number.

## Requirements

* Linux 4.18 or newer

## Capabilities

* `cap_sys_resource` is required to release the rlimit memlock which is
necessary to be able to load BPF programs
* `cap_net_raw` is required to open raw sockets, to which our BPF program needs
to attach
* `cap_perfmon` is required to create a kernel perf buffer for exporting packet
data into user space
Requires root, or the following capabilities:

| Kernel | Capabilities |
|-------------|-------------------------------------------------------|
| 5.11 or newer | `cap_bpf`, `cap_perfmon`, `cap_net_raw` |
| 5.8 - 5.11 | `cap_bpf`, `cap_perfmon`, `cap_net_raw`, `cap_sys_resource` |
| older | `cap_sys_admin`, `cap_net_raw` |

* `cap_bpf` loads the BPF program and creates its maps.
* `cap_perfmon` opens the perf buffer that carries packet headers to user space.
* `cap_net_raw` opens the raw socket the program attaches to.

Example:

```bash
sudo setcap cap_bpf,cap_perfmon,cap_net_raw+ep binary
```

### Debian and Ubuntu: `perf_event_paranoid`

Debian and Ubuntu kernels have `kernel.perf_event_paranoid` levels at which `cap_perfmon` is
not allowed to open the perf buffer. This leades to the error:

```
Unable to connect kernel perf event reader, err: failed to create perf ring for CPU 0: can't create perf event: permission denied
```

Check the level with `sysctl kernel.perf_event_paranoid`. If it is 3 or
higher, either lower it to 2 using:

```bash
# temporarily
sudo sysctl kernel.perf_event_paranoid=2
# or persist across reboots
echo 'kernel.perf_event_paranoid = 2' | sudo tee /etc/sysctl.d/60-perf-event-paranoid.conf
```

or grant `cap_sys_admin` instead of `cap_perfmon`, or run as root.

## Building

The compiled BPF objects (`packetdump/bpf_bpf{el,eb}.{go,o}`) are committed, so
a plain `go build ./...` needs only Go. Changing `packetdump/bpf/bpf.c` also requires
`clang`, `llvm` and `libbpf`. These can be installed using:

```bash
sudo apt install clang llvm libbpf-dev
```

## Testing

```bash
go test -race ./...
```

Full example:
The end-to-end test injects packets on `lo` and checks every decoded field and can be executed using:

```bash
sudo setcap cap_sys_resource,cap_net_raw,cap_perfmon+ep binary
go test -c -race -o packetdump.test ./packetdump
sudo ./packetdump.test -test.run TestEndToEndLoopback -test.v
```
Loading
Loading