Skip to content

Commit 27346fa

Browse files
feat: Add ebpf exporter
* Refactor cgroup detection into separate file. We should be able to use the struct in different collectors * Use go routines in perf collector to update Signed-off-by: Mahendra Paipuri <mahendra.paipuri@gmail.com>
1 parent cd6de29 commit 27346fa

35 files changed

+94219
-172
lines changed

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ else
4040
test-docker := test-docker
4141
endif
4242

43+
# Base test flags
44+
test-flags := -covermode=atomic -race
45+
4346
# Use CGO for api and GO for ceems_exporter.
4447
PROMU_TEST_CONF ?= .promu-go-test.yml
4548
ifeq ($(CGO_BUILD), 1)
@@ -67,8 +70,13 @@ else
6770

6871
# go test flags
6972
coverage-file := coverage-go.out
73+
74+
# If running in CI add -exec sudo flags to run tests that require privileges
75+
ifeq ($(CI), true)
76+
test-flags := $(test-flags) -exec sudo
77+
endif
7078
endif
71-
test-flags := -covermode=atomic -coverprofile=$(coverage-file).tmp -race
79+
test-flags := $(test-flags) -coverprofile=$(coverage-file).tmp
7280

7381
ifeq ($(GOHOSTOS), linux)
7482
test-e2e := test-e2e

Makefile.common

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ ifeq ($(CGO_BUILD), 1)
193193
endif
194194
@echo ">> building test binaries"
195195
$(PROMU_TEST) build --prefix $(PREFIX) $(PROMU_BINARIES)
196+
endif
197+
ifeq ($(CGO_BUILD), 0)
198+
@echo ">> building bpf assets"
199+
$(MAKE) -C ./pkg/collector/bpf clean
200+
$(MAKE) -C ./pkg/collector/bpf
196201
endif
197202
@echo ">> building binaries"
198203
$(PROMU) build --prefix $(PREFIX) $(PROMU_BINARIES)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
| | |
55
| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
6-
| CI/CD | [![ci](https://github.com/mahendrapaipuri/ceems/workflows/CI/badge.svg)](https://github.com/mahendrapaipuri/ceems) [![CircleCI](https://dl.circleci.com/status-badge/img/circleci/8jSYT1wyKY8mKQRTqNLThX/TzM1Mr3AEAqmehnoCde19R/tree/main.svg?style=svg&circle-token=28db7268f3492790127da28e62e76b0991d59c8b)](https://dl.circleci.com/status-badge/redirect/circleci/8jSYT1wyKY8mKQRTqNLThX/TzM1Mr3AEAqmehnoCde19R/tree/main) [![Coverage](https://img.shields.io/badge/Coverage-76.0%25-brightgreen)](https://github.com/mahendrapaipuri/ceems/actions/workflows/ci.yml?query=branch%3Amain) |
6+
| CI/CD | [![ci](https://github.com/mahendrapaipuri/ceems/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mahendrapaipuri/ceems/actions/workflows/ci.yml?query=branch%3Amain) [![CircleCI](https://dl.circleci.com/status-badge/img/circleci/8jSYT1wyKY8mKQRTqNLThX/TzM1Mr3AEAqmehnoCde19R/tree/main.svg?style=svg&circle-token=28db7268f3492790127da28e62e76b0991d59c8b)](https://dl.circleci.com/status-badge/redirect/circleci/8jSYT1wyKY8mKQRTqNLThX/TzM1Mr3AEAqmehnoCde19R/tree/main) [![Coverage](https://img.shields.io/badge/Coverage-76.0%25-brightgreen)](https://github.com/mahendrapaipuri/ceems/actions/workflows/ci.yml?query=branch%3Amain) |
77
| Docs | [![docs](https://img.shields.io/badge/docs-passing-green?style=flat&link=https://mahendrapaipuri.github.io/ceems/docs/)](https://mahendrapaipuri.github.io/ceems/) |
88
| Package | [![Release](https://img.shields.io/github/v/release/mahendrapaipuri/ceems.svg?include_prereleases)](https://github.com/mahendrapaipuri/ceems/releases/latest) |
99
| Meta | [![GitHub License](https://img.shields.io/github/license/mahendrapaipuri/ceems)](https://github.com/mahendrapaipuri/ceems) [![Go Report Card](https://goreportcard.com/badge/github.com/mahendrapaipuri/ceems)](https://goreportcard.com/report/github.com/mahendrapaipuri/ceems) [![code style](https://img.shields.io/badge/code%20style-gofmt-blue.svg)](https://pkg.go.dev/cmd/gofmt) |

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.22.5
44

55
require (
66
github.com/alecthomas/kingpin/v2 v2.4.0
7+
github.com/cilium/ebpf v0.11.0
78
github.com/containerd/cgroups/v3 v3.0.4-0.20240117155926-c00d22e55fef
89
github.com/go-chi/httprate v0.14.1
910
github.com/go-kit/log v0.2.1
@@ -30,7 +31,6 @@ require (
3031
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect
3132
github.com/beorn7/perks v1.0.1 // indirect
3233
github.com/cespare/xxhash/v2 v2.3.0 // indirect
33-
github.com/cilium/ebpf v0.11.0 // indirect
3434
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
3535
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
3636
github.com/docker/go-units v0.5.0 // indirect

pkg/collector/bpf/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Ignore objs and deps
2+
objs/
3+
deps/

pkg/collector/bpf/Makefile

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
.PHONY: all clean
2+
.SUFFIXES:
3+
4+
include ./Makefile.common
5+
6+
VFSDIR := vfs/
7+
NETWORKDIR := network/
8+
BPFTESTDIR := test/
9+
10+
NETWORK = bpf_network.o
11+
VFS = bpf_vfs.o bpf_vfs_v511.o bpf_vfs_v62.o
12+
# BPFTEST = bpf_lseek.o
13+
14+
OBJSDIR := objs/
15+
DEPSDIR := deps/
16+
17+
VFSOBJ := $(addprefix $(OBJSDIR),$(VFS))
18+
NETWORKOBJ := $(addprefix $(OBJSDIR),$(NETWORK))
19+
TESTOBJ := $(addprefix $(OBJSDIR),$(BPFTEST))
20+
OBJS := $(VFSOBJ) $(NETWORKOBJ) $(TESTOBJ)
21+
LLOBJS := $(patsubst $(OBJSDIR)%.o,$(OBJSDIR)%.ll,$(OBJS))
22+
DEPS := $(patsubst $(OBJSDIR)%.ll,$(DEPSDIR)%.d,$(LLOBJS))
23+
24+
all: $(OBJS) $(DEPS)
25+
26+
# NB: https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html
27+
$(OBJS): | $(OBJSDIR)
28+
$(DEPS): | $(DEPSDIR)
29+
$(LLOBJS): | $(OBJSDIR)
30+
31+
$(OBJSDIR):
32+
mkdir $(OBJSDIR)
33+
34+
$(DEPSDIR):
35+
mkdir $(DEPSDIR)
36+
37+
define DEFINE_VARIANT
38+
VAR := $1
39+
deps/bpf_vfs_$$(VAR).d: vfs/bpf_vfs.c
40+
endef
41+
42+
# Generic build targets for each sub-dir
43+
44+
$(eval $(call DEFINE_VARIANT,v511))
45+
$(eval $(call DEFINE_VARIANT,v62))
46+
47+
# Build only for relevant architectures
48+
ifeq ($(BPF_TARGET_COMPILE),1)
49+
50+
# VFSDIR
51+
objs/%.ll: $(VFSDIR)%.c
52+
$(CLANG) $(CLANG_FLAGS) -D__KERNEL_POST_v62 -c $< -o $@
53+
54+
objs/%_v511.ll:
55+
$(CLANG) $(CLANG_FLAGS) -D__KERNEL_PRE_v511 -c $< -o $@
56+
57+
objs/%_v62.ll:
58+
$(CLANG) $(CLANG_FLAGS) -D__KERNEL_POST_v512_PRE_v62 -c $< -o $@
59+
60+
$(DEPSDIR)%.d: $(VFSDIR)%.c
61+
$(CLANG) $(CLANG_FLAGS) -D__KERNEL_POST_v62 -MM -MP -MT $(patsubst $(DEPSDIR)%.d, $(OBJSDIR)%.ll, $@) $< > $@
62+
63+
$(DEPSDIR)%_v511.d:
64+
$(CLANG) $(CLANG_FLAGS) -D__KERNEL_PRE_v511 -MM -MP -MT $(patsubst $(DEPSDIR)%.d, $(OBJSDIR)%.ll, $@) $< > $@
65+
66+
$(DEPSDIR)%_v62.d:
67+
$(CLANG) $(CLANG_FLAGS) -D__KERNEL_POST_v512_PRE_v62 -MM -MP -MT $(patsubst $(DEPSDIR)%.d, $(OBJSDIR)%.ll, $@) $< > $@
68+
69+
# NETWORKDIR
70+
objs/%.ll: $(NETWORKDIR)%.c
71+
$(CLANG) $(CLANG_FLAGS) -c $< -o $@
72+
73+
$(DEPSDIR)%.d: $(NETWORKDIR)%.c
74+
$(CLANG) $(CLANG_FLAGS) -MM -MP -MT $(patsubst $(DEPSDIR)%.d, $(OBJSDIR)%.ll, $@) $< > $@
75+
76+
# BPFTESTDIR
77+
objs/%.ll: $(BPFTESTDIR)%.c
78+
$(CLANG) $(CLANG_FLAGS) -c $< -o $@
79+
80+
$(DEPSDIR)%.d: $(BPFTESTDIR)%.c
81+
$(CLANG) $(CLANG_FLAGS) -MM -MP -MT $(patsubst $(DEPSDIR)%.d, $(OBJSDIR)%.ll, $@) $< > $@
82+
83+
# Remaining objects are built without mcpu=v2
84+
objs/%.o: objs/%.ll
85+
$(LLC) $(LLC_FLAGS) -filetype=obj $< -o $@
86+
87+
# include dependencies, see https://lists.gnu.org/archive/html/make-w32/2004-03/msg00062.html
88+
ifeq (,$(filter $(MAKECMDGOALS),clean run-test))
89+
-include $(DEPS)
90+
endif
91+
92+
endif
93+
94+
# the 'test' target is already taken
95+
run-test:
96+
$(MAKE) -C tests test
97+
98+
# SUBDIRS=tests
99+
100+
clean:
101+
@$(ECHO_CLEAN)
102+
$(QUIET) $(foreach TARGET,$(SUBDIRS), \
103+
$(MAKE) -C $(TARGET) clean)
104+
$(QUIET)rm -f $(OBJSDIR)*.{o,ll,i,s}
105+
$(QUIET)rm -f $(DEPSDIR)*.d

pkg/collector/bpf/Makefile.common

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
SHELL=/bin/bash # needed for the *.{o,ll,i,s} pattern in the clean target
2+
3+
CLANG ?= clang
4+
LLC ?= llc
5+
6+
# Build the BPF programs for the detected architecture, default to x86, and
7+
# allow easy overriding by using ?= for cross-compilation
8+
# UNAME_M := $(shell uname -m)
9+
# ifeq ($(UNAME_M),x86_64)
10+
# BPF_TARGET_ARCH ?= x86
11+
# endif
12+
# ifeq ($(UNAME_M),aarch64)
13+
# BPF_TARGET_ARCH ?= arm64
14+
# endif
15+
16+
# Get cross-compiling flags from GOARCH env variable
17+
# Endians are picked up https://github.com/cilium/ebpf/blob/625b0a910e1ba666e483e75b149880ce3b54dc85/cmd/bpf2go/gen/target.go#L14-L28
18+
BPF_TARGET_ARCH ?= x86
19+
BPF_TARGET_MARCH ?= bpf
20+
BPF_TARGET_COMPILE ?= 1
21+
ifeq ($(GOARCH),386)
22+
BPF_TARGET_ARCH = x86
23+
BPF_TARGET_MARCH = bpfel
24+
else ifeq ($(GOARCH),amd64)
25+
BPF_TARGET_ARCH = x86
26+
BPF_TARGET_MARCH = bpfel
27+
else ifeq ($(GOARCH),arm64)
28+
BPF_TARGET_ARCH = arm64
29+
BPF_TARGET_MARCH = bpfel
30+
else ifeq ($(GOARCH),mpis)
31+
BPF_TARGET_ARCH = mips
32+
BPF_TARGET_MARCH = bpfeb
33+
else ifeq ($(GOARCH),ppc64)
34+
BPF_TARGET_ARCH = powerpc
35+
BPF_TARGET_MARCH = bpfeb
36+
else ifeq ($(GOARCH),ppc64le)
37+
BPF_TARGET_ARCH = powerpc
38+
BPF_TARGET_MARCH = bpfel
39+
else ifeq ($(GOARCH),riscv64)
40+
BPF_TARGET_ARCH = riscv
41+
BPF_TARGET_MARCH = bpfel
42+
else ifeq ($(GOARCH),s390x)
43+
BPF_TARGET_ARCH = s390
44+
BPF_TARGET_MARCH = bpfeb
45+
endif
46+
47+
# Do not compile BPF assets for mipsle, mips64 and mips64le architectures
48+
ifeq ($(GOARCH),mipsle)
49+
BPF_TARGET_COMPILE = 0
50+
endif
51+
ifeq ($(GOARCH),mips64)
52+
BPF_TARGET_COMPILE = 0
53+
endif
54+
ifeq ($(GOARCH),mips64le)
55+
BPF_TARGET_COMPILE = 0
56+
endif
57+
58+
ROOT_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
59+
60+
IDIR = $(ROOT_DIR)include/
61+
LIBBPF = $(ROOT_DIR)libbpf/
62+
LDIR = $(ROOT_DIR)lib
63+
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
64+
65+
FLAGS := -I$(ROOT_DIR) \
66+
-Wall -Werror \
67+
-Wno-address-of-packed-member -Wno-compare-distinct-pointer-types -Wno-unknown-warning-option \
68+
-O2
69+
70+
CLANG_FLAGS += $(FLAGS) -I $(LIBBPF) -I $(IDIR) -I $(LDIR) -target bpf -emit-llvm -g -D__TARGET_ARCH_$(BPF_TARGET_ARCH) -fdebug-default-version=4
71+
LLC_FLAGS := -march=$(BPF_TARGET_MARCH) -mcpu=v2 -mattr=dwarfris
72+
LLC_FLAGS_ALU32 := -march=$(BPF_TARGET_MARCH) -mcpu=v3 -mattr=dwarfris

pkg/collector/bpf/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* SPDX-License-Identifier: (GPL-3.0-only) */
2+
3+
#ifndef MAX_MAP_ENTRIES
4+
#define MAX_MAP_ENTRIES 256
5+
#endif
6+
7+
#define FUNC_INLINE static inline __attribute__((always_inline))
8+
9+
/*
10+
* Following define is to assist VSCode Intellisense so that it treats
11+
* __builtin_preserve_access_index() as a const void * instead of a
12+
* simple void (because it doesn't have a definition for it). This stops
13+
* Intellisense marking all _(P) macros (used in probe_read()) as errors.
14+
* To use this, just define VSCODE in 'C/C++: Edit Configurations (JSON)'
15+
* in the Command Palette in VSCODE (F1 or View->Command Palette...):
16+
* "defines": ["VSCODE"]
17+
* under configurations.
18+
*/
19+
#ifdef VSCODE
20+
const void *__builtin_preserve_access_index(void *);
21+
#endif
22+
#define _(P) (__builtin_preserve_access_index(P))
23+
24+
#ifndef likely
25+
# define likely(X) __builtin_expect(!!(X), 1)
26+
#endif
27+
28+
#ifndef unlikely
29+
# define unlikely(X) __builtin_expect(!!(X), 0)
30+
#endif
31+
32+
#ifndef __inline__
33+
# define __inline__ __attribute__((always_inline))
34+
#endif
35+
36+
#define DEBUG
37+
#ifdef DEBUG
38+
/* Only use this for debug output. Notice output from bpf_trace_printk()
39+
* ends up in /sys/kernel/debug/tracing/trace_pipe
40+
*/
41+
#define bpf_debug(fmt, ...) \
42+
({ \
43+
char ____fmt[] = fmt; \
44+
bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
45+
})
46+
#else
47+
#define bpf_debug(fmt, ...){;}
48+
#endif
49+
50+
// Just to ensure that we can use vfs_write/vfs_read calls
51+
// Picked from https://github.com/torvalds/linux/blob/master/tools/include/linux/types.h#L56
52+
#ifndef __user
53+
#define __user
54+
#endif
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* SPDX-License-Identifier: (GPL-3.0-only) */
2+
3+
#ifndef _NET_SHARED_H
4+
#define _NET_SHARED_H
5+
6+
#define AF_INET 2
7+
#define AF_INET6 10
8+
9+
#define ETH_ALEN 6
10+
#define ETH_P_802_3_MIN 0x0600
11+
#define ETH_P_8021Q 0x8100
12+
#define ETH_P_8021AD 0x88A8
13+
#define ETH_P_IP 0x0800
14+
#define ETH_P_IPV6 0x86DD
15+
#define ETH_P_ARP 0x0806
16+
#define IPPROTO_ICMPV6 58
17+
18+
#define TC_ACT_OK 0
19+
#define TC_ACT_SHOT 2
20+
21+
#define IFNAMSIZ 16
22+
23+
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
24+
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
25+
#define bpf_ntohs(x) __builtin_bswap16(x)
26+
#define bpf_htons(x) __builtin_bswap16(x)
27+
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
28+
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
29+
#define bpf_ntohs(x) (x)
30+
#define bpf_htons(x) (x)
31+
#else
32+
# error "Endianness detection needs to be set up for your compiler?!"
33+
#endif
34+
35+
#endif

0 commit comments

Comments
 (0)