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
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@ INSTALLPATH = $(installprefix)

.PHONY: all clean

all: srcdir docdir
all: srcdir docdir testdir

srcdir:
cd src; make
docdir:
cd docs; make man

testdir: srcdir
cd test; make

test: FORCE
cd test; make test

Expand All @@ -55,7 +58,7 @@ pkg: all

FORCE:

clean: srcclean docclean
clean: srcclean docclean testclean

distclean: clean distclean_src

Expand All @@ -65,6 +68,8 @@ docclean:
cd docs; make clean
distclean_src:
cd src; make distclean
testclean:
cd test; make clean

install: srcinstall includeinstall docinstall

Expand Down
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,33 @@ The key components are
from BPF programs to userspace via the shared ring buffer.
Each tuner has an associated set of tunables that it manages.

- optional strategies: a tuner can specify multiple strategies;
after running for a while a strategy times out and we assess
if a better strategy is available. Each strategy specifies a
- name
- description
- timeout
- evaluation function
- set of BPF program names in tuner associated with strategy

Strategies are optional and should be set in the tuner init()
method via bpftune_strategies_add(). See test/strategy
for a coded example. When a strategy times out, the various
evaluation functions are called and the highest-value evaluation
dictates the next stratgey.

Strategies provide a way of providing multiple schemes for
auto-tuning the same set of tunables, where the choice is
guided by an evaluation of the effectiveness of the strategies.

- events specify a
- tuner id: which tuner the event is destined for
- a scenario: what happened
- an associated netns (if supported)
- information about the event (IP address etc)

- the tuner then responds to the event with a strategy; increase
or decrease a tunable value, etc. Describing the event
- the tuner then responds to the event guided by the active strategy;
increase or decrease a tunable value, etc. Describing the event
in the log is key; this allows an admin to understand what
changed and why.

Expand Down Expand Up @@ -180,6 +199,12 @@ To build the following packages are needed (names may vary by distro);
- llvm >= 11
- python3-docutils

From the kernel side, the kernel needs to support BPF ring buffer
(around the 5.6 kernel, though 5.4 is supported on Oracle Linux
as ring buffer support was backported), and kernel BTF is
required (CONFIG_DEBUG_INFO_BTF=y). Verify /sys/kernel/btf/vmlinux
is present.

To enable bpftune as a service

```
Expand Down
14 changes: 14 additions & 0 deletions include/bpftune/bpftune.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,18 @@ struct bpftuner_netns {
enum bpftune_state state;
};

struct bpftuner;

struct bpftuner_strategy {
const char *name;
const char *description;
/* return a number to compare with other strategies */
int (*evaluate)(struct bpftuner *tuner, struct bpftuner_strategy *strategy);
unsigned long timeout; /* time in seconds until evaluation */
const char **bpf_progs; /* programs to load in BPF skeleton for this
* strategy; if NULL, all */
};

struct bpftuner {
unsigned int id;
enum bpftune_state state;
Expand All @@ -151,6 +163,8 @@ struct bpftuner {
void *obj;
int (*init)(struct bpftuner *tuner);
void (*fini)(struct bpftuner *tuner);
struct bpftuner_strategy **strategies;
struct bpftuner_strategy *strategy;
void *ring_buffer_map;
int ring_buffer_map_fd;
void *corr_map;
Expand Down
10 changes: 10 additions & 0 deletions include/bpftune/libbpftune.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ static inline const char *bpftuner_tunable_name(struct bpftuner *tuner,
#define bpftuner_for_each_tunable(tuner, tunable) \
for (unsigned int __itun = 0; (tunable = bpftuner_tunable(tuner, __itun)); __itun++)

#define bpftuner_for_each_strategy(tuner, strategy) \
for (unsigned int __s = 0; (strategy = tuner->strategies[__s]); __s++)

int bpftuner_tunable_sysctl_write(struct bpftuner *tuner,
unsigned int tunable,
unsigned int scenario,
Expand Down Expand Up @@ -168,6 +171,7 @@ void bpftuner_tunables_fini(struct bpftuner *tuner);
tuner->ring_buffer_map = __lskel->maps.ring_buffer_map;\
tuner->netns_map = __lskel->maps.netns_map; \
} \
bpftuner_bpf_set_autoload(tuner); \
} while (0); \
bpftune_cap_drop(); \
if (__err) { \
Expand Down Expand Up @@ -291,4 +295,10 @@ int bpftuner_netns_fd_from_cookie(struct bpftuner *tuner, unsigned long cookie);
int bpftune_module_load(const char *name);
int bpftune_module_unload(const char *name);

int bpftuner_strategy_set(struct bpftuner *tuner, struct bpftuner_strategy *strategy);
int bpftuner_strategies_add(struct bpftuner *tuner, struct bpftuner_strategy **strategies,
struct bpftuner_strategy *default_strategy);
bool bpftuner_bpf_prog_in_strategy(struct bpftuner *tuner, const char *prog);
void bpftuner_bpf_set_autoload(struct bpftuner *tuner);

#endif /* __LIBBPFTUNE_H */
2 changes: 1 addition & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ CFLAGS = -fPIC -Wall -Wextra -march=native -g -I../include -std=c99

CFLAGS += -DBPFTUNE_VERSION='"$(BPFTUNE_VERSION)"' $(INCLUDES)

LDLIBS = -lbpf -ldl -lm -lcap -lnl-3 -lpthread -lnl-route-3
LDLIBS = -lbpf -ldl -lm -lrt -lcap -lnl-3 -lpthread -lnl-route-3

LDFLAGS += -L. -L/usr/local/lib64

Expand Down
138 changes: 138 additions & 0 deletions src/libbpftune.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#include <mntent.h>
#include <sys/capability.h>
#include <pthread.h>
#include <signal.h>
#include <time.h>

unsigned short bpftune_learning_rate;

Expand Down Expand Up @@ -325,6 +327,10 @@ int bpftuner_cgroup_attach(struct bpftuner *tuner, const char *prog_name,
struct bpf_program *prog;
const char *cgroup_dir;

/* if cgroup prog is not in current strategy prog list, skip attach */
if (!bpftuner_bpf_prog_in_strategy(tuner, prog_name))
return 0;

err = bpftune_cap_add();
if (err)
return err;
Expand Down Expand Up @@ -364,6 +370,10 @@ void bpftuner_cgroup_detach(struct bpftuner *tuner, const char *prog_name,
int prog_fd, cgroup_fd, err = 0;
struct bpf_program *prog;

/* if cgroup prog is not in current strategy prog list, skip attach */
if (!bpftuner_bpf_prog_in_strategy(tuner, prog_name))
return;

err = bpftune_cap_add();
if (err)
return;
Expand Down Expand Up @@ -617,6 +627,7 @@ struct bpftuner *bpftuner_init(const char *path)
bpftune_log(LOG_ERR, "could not allocate tuner\n");
return NULL;
}
tuner->name = path;

bpftune_cap_add();
/* if file appears via inotify we may get "file too short" errors;
Expand Down Expand Up @@ -1503,3 +1514,130 @@ int bpftune_module_unload(const char *name)
bpftune_cap_drop();
return ret;
}

static void bpftuner_strategy_update(struct bpftuner *tuner)
{
struct bpftuner_strategy *strategy, *max_strategy = NULL;
int curr, max = 0;

if (!tuner->strategies)
return;

bpftune_log(LOG_DEBUG, "%s: updating strategy...\n", tuner->name);

bpftuner_for_each_strategy(tuner, strategy) {
curr = strategy->evaluate(tuner, strategy);
if (curr < max)
continue;
max = curr;
max_strategy = strategy;
}
if (max_strategy && max_strategy != tuner->strategy)
bpftuner_strategy_set(tuner, max_strategy);
}

static void bpftuner_strategy_timeout(sigval_t sigval)
{
struct bpftuner *tuner = sigval.sival_ptr;

if (tuner)
bpftuner_strategy_update(tuner);
}

int bpftuner_strategy_set(struct bpftuner *tuner,
struct bpftuner_strategy *strategy)
{
bpftune_log(LOG_DEBUG, "setting stragegy for tuner '%s' to '%s': %s\n",
tuner->name, strategy->name, strategy->description);
int err = 0;

if (!strategy)
return 0;

if (tuner->strategy) {
/* clean up for current strategy */
bpftune_log(LOG_DEBUG, "%s: cleaning up current strategy '%s'\n",
tuner->name, strategy->name);
tuner->fini(tuner);
}
/* arm timer for timeout */
if (strategy->timeout) {
struct sigevent sev = {};
struct itimerspec its = {};
timer_t tid;

sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = &bpftuner_strategy_timeout;
sev.sigev_value.sival_ptr = tuner;

if (timer_create(CLOCK_REALTIME, &sev, &tid)
== -1) {
err = -errno;
bpftune_log(LOG_DEBUG, "%s: could not arm timer for strategy '%s'\n",
strerror(-err));
return 0;
}
its.it_value.tv_sec = strategy->timeout;
if (timer_settime(tid, 0, &its, NULL)) {
err = -errno;
bpftune_log(LOG_DEBUG, "%s: could not arm timer for strategy '%s: %s'\n",
tuner->name, strategy->name, strerror(-err));
return 0;
}
}
if (!err) {
tuner->strategy = strategy;
err = tuner->init(tuner);
}
return err;
}

int bpftuner_strategies_add(struct bpftuner *tuner, struct bpftuner_strategy **strategies,
struct bpftuner_strategy *default_strategy)
{
if (!strategies || tuner->strategies)
return 0;
tuner->strategies = strategies;
if (default_strategy)
return bpftuner_strategy_set(tuner, default_strategy);
bpftuner_strategy_update(tuner);
return 0;
}

bool bpftuner_bpf_prog_in_strategy(struct bpftuner *tuner, const char *prog)
{
const char **progs;
int i;

if (!tuner->strategy || !tuner->strategy->bpf_progs)
return true;
progs = tuner->strategy->bpf_progs;

for (i = 0; progs[i] != NULL; i++) {
if (strcmp(prog, progs[i]) == 0)
return true;
}
return false;
}

void bpftuner_bpf_set_autoload(struct bpftuner *tuner)
{
struct bpf_program *prog = NULL;
int err;

if (!tuner->strategy || !tuner->strategy->bpf_progs)
return;

bpf_object__for_each_program(prog, tuner->obj) {
const char *name = bpf_program__name(prog);

if (bpftuner_bpf_prog_in_strategy(tuner, name))
continue;
err = bpf_program__set_autoload(prog, false);
if (err) {
bpftune_log(LOG_ERR, "%s: could not disable autoload for prog '%s' for strategy '%s': %s\n",
tuner->name, name,
tuner->strategy->name, strerror(err));
}
}
}
4 changes: 4 additions & 0 deletions src/libbpftune.map
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,17 @@ LIBBPFTUNE_0.1.1 {
bpftuner_tunable_update;
bpftuner_fini;
bpftuner_bpf_fini;
bpftuner_bpf_set_autoload;
bpftuner_bpf_prog_in_strategy;
bpftuner_tunables_fini;
bpftune_netns_cookie_supported;
bpftuner_netns_init;
bpftuner_netns_fini;
bpftuner_netns_from_cookie;
bpftuner_netns_fd_from_cookie;
bpftuner_ring_buffer_map_fd;
bpftuner_strategy_set;
bpftuner_strategies_add;
bpftune_ring_buffer_init;
bpftune_ring_buffer_poll;
bpftune_ring_buffer_fini;
Expand Down
14 changes: 11 additions & 3 deletions test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
# Boston, MA 021110-1307, USA.
#


PERF_TESTS = iperf3_test qperf_test

TUNER_TESTS = support_test log_test service_test inotify_test cap_test \
sample_test sample_legacy_test \
strategy_test strategy_legacy_test \
sysctl_test sysctl_legacy_test sysctl_netns_test \
netns_test netns_legacy_test \
backlog_test backlog_legacy_test \
Expand Down Expand Up @@ -53,14 +55,20 @@ INSTALLPATH = $(installprefix)/lib/tcptune_test/
install_sh_PROGRAM = install
install_sh_DIR = install -dv

all: $(PROGS)
all: strategydir $(PROGS)

strategydir:
cd strategy; make

PHONY: clean

clean:
clean: strategyclean
rm -f $(PROGS)

test: $(TESTS)
strategyclean:
cd strategy; make clean

test: all $(TESTS)

test_perf: $(PERF_TESTS)

Expand Down
Loading