Skip to content

Commit 4df319c

Browse files
committed
Add --use-libxdp option and config, load libxdp dynamically
1 parent 3e2c01f commit 4df319c

8 files changed

Lines changed: 147 additions & 28 deletions

File tree

‎Makefile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ endif
3636
ifneq ($(USE_LIBXDP),)
3737
BPF_CFLAGS += -DMIMIC_USE_LIBXDP
3838
CFLAGS += -DMIMIC_USE_LIBXDP
39-
mimic_link_libs += -lxdp
39+
# mimic_link_libs += -lxdp
4040
endif
4141

4242
# Whether to use argp-standalone

‎docs/mimic.1.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
`-x, --xdp-mode`
3131
: Force XDP attach mode, either skb or native
3232

33+
`-X, --use-libxdp`
34+
: Use libxdp Use libxdp instead of libbpf to load XDP program.
35+
: libxdp supports chaining multiple XDP programs on one interface. Mimic loads libxdp dynamically using dlopen.
36+
3337
`-h, --handshake`
3438
: Controls retry behaviour of initiating connection (see [**CONFIGURATION/Handshake and Keepalive Parameters**](#handshake-and-keepalive-parameters))
3539

@@ -114,7 +118,7 @@ See **/usr/share/doc/mimic/eth0.conf.example** for detailed examples.
114118
`log.verbosity`
115119
: Controls how much information should be printed. Log level equal to or higher (in number) than log verbosity will be discarded. Both number and string matching log levels are accepted. Number must be greater than or equal to 0. Defaults to info (2). Available levels are: 0 - error (cannot be discarded), 1 - warn, 2 - info, 3 - debug, 4 - trace.
116120

117-
`handshake`, `keepalive`, `padding`, `max_window`
121+
`xdp_mode`, `use_libxdp`, `handshake`, `keepalive`, `padding`, `max_window`
118122
: See [**OPTIONS**](#options).
119123

120124
`filter`

‎src/config.c‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ int parse_config_file(FILE* file, struct run_args* args) {
286286
} else if (strcmp(k, "xdp_mode") == 0) {
287287
args->xdp_mode = try(parse_xdp_mode(v));
288288

289+
} else if (strcmp(k, "use_libxdp") == 0) {
290+
__s16 result = 0;
291+
try(parse_bool(v, &result));
292+
args->use_libxdp = result;
293+
289294
} else if (!try(parse_setting(k, v, &args->gsettings))) {
290295
ret(-EINVAL, _("unknown key '%s'"), k);
291296
}

‎src/libxdp.c‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include <dlfcn.h>
2+
#include <errno.h>
3+
#include <xdp/libxdp.h>
4+
5+
#include "common/try.h"
6+
#include "libxdp.h"
7+
8+
static void *libxdp_dl = NULL;
9+
10+
DLSYM_PROTOTYPE(libxdp_set_print) = NULL;
11+
DLSYM_PROTOTYPE(xdp_program__from_bpf_obj) = NULL;
12+
DLSYM_PROTOTYPE(xdp_program__attach) = NULL;
13+
DLSYM_PROTOTYPE(xdp_program__detach) = NULL;
14+
DLSYM_PROTOTYPE(xdp_program__close) = NULL;
15+
16+
static int dlsym_many_or_warnv(void *dl, va_list ap) {
17+
void (**fn)(void);
18+
19+
while ((fn = va_arg(ap, typeof(fn)))) {
20+
void (*tfn)(void);
21+
const char *symbol;
22+
23+
symbol = va_arg(ap, typeof(symbol));
24+
25+
tfn = (typeof(tfn))dlsym(dl, symbol);
26+
if (!tfn) ret(-ELIBBAD, "can't find symbol '%s': %s", symbol, dlerror());
27+
*fn = tfn;
28+
}
29+
30+
return 0;
31+
}
32+
33+
static int dlopen_many_sym_or_warn_sentinel(void **dlp, const char *filename, ...) {
34+
void *dl = NULL;
35+
int retcode;
36+
37+
if (*dlp) return 0;
38+
39+
dl = dlopen(filename, RTLD_NOW | RTLD_NODELETE);
40+
if (!dl) ret(-EOPNOTSUPP, "%s is not installed: %s", filename, dlerror());
41+
42+
log_debug("loaded '%s' via dlopen()", filename);
43+
44+
va_list ap;
45+
va_start(ap, filename);
46+
retcode = dlsym_many_or_warnv(dl, ap);
47+
va_end(ap);
48+
if (retcode < 0) goto cleanup;
49+
50+
*dlp = dl;
51+
return 1;
52+
cleanup:
53+
if (dl) dlclose(dl);
54+
return retcode;
55+
}
56+
57+
#define dlopen_many_sym_or_warn(dlp, filename, ...) \
58+
dlopen_many_sym_or_warn_sentinel(dlp, filename, __VA_ARGS__, NULL)
59+
60+
int dlopen_libxdp() {
61+
return dlopen_many_sym_or_warn(
62+
&libxdp_dl, "libxdp.so.1", DLSYM_ARG(libxdp_set_print), DLSYM_ARG(xdp_program__from_bpf_obj),
63+
DLSYM_ARG(xdp_program__attach), DLSYM_ARG(xdp_program__detach), DLSYM_ARG(xdp_program__close));
64+
}

‎src/libxdp.h‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#ifndef MIMIC_LIBXDP_H
2+
#define MIMIC_LIBXDP_H
3+
4+
#include <assert.h>
5+
#include <xdp/libxdp.h>
6+
7+
#define DLSYM_PROTOTYPE(symbol) typeof(symbol)* sym_##symbol
8+
9+
#define DLSYM_ARG(arg) \
10+
({ \
11+
assert(__builtin_types_compatible_p(typeof(sym_##arg), typeof(&arg))); \
12+
&sym_##arg; \
13+
}), \
14+
#arg
15+
16+
extern DLSYM_PROTOTYPE(libxdp_set_print);
17+
extern DLSYM_PROTOTYPE(xdp_program__from_bpf_obj);
18+
extern DLSYM_PROTOTYPE(xdp_program__attach);
19+
extern DLSYM_PROTOTYPE(xdp_program__detach);
20+
extern DLSYM_PROTOTYPE(xdp_program__close);
21+
22+
int dlopen_libxdp();
23+
24+
#endif

‎src/log.c‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ void log_destroy(enum log_level level, struct conn_tuple* conn, enum destroy_typ
8383
log_conn(level, conn, _("connection destroyed (%s)"), reason);
8484
}
8585

86+
// TODO: filter other messages like:
87+
// - turn 'libbpf: elf: skipping unrecognized data section' into Trace
88+
// - turn 'libxdp: Error attaching XDP program ...' and 'XDP mode not supported; try using SKB mode' into Warn
8689
int libbpf_print_fn(enum libbpf_print_level bpf_level, const char* format, va_list args) {
8790
int ret = 0;
8891
if (bpf_level == LIBBPF_WARN && LOG_ALLOW_WARN) {

‎src/main.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct args {
2626
struct filter_settings gsettings;
2727
unsigned int filter_count;
2828
int xdp_mode;
29+
bool use_libxdp;
2930
} run;
3031
struct show_args {
3132
const char* ifname;

‎src/run.c‎

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
#include <unistd.h>
2828

2929
#ifdef MIMIC_USE_LIBXDP
30-
#include <xdp/libxdp.h>
30+
#include "libxdp.h"
3131
#endif
3232

3333
#include "bpf_skel.h"
@@ -44,6 +44,9 @@ static const struct argp_option options[] = {
4444
{"filter", 'f', N_("FILTER"), 0,
4545
N_("Specify what packets to process. This may be specified for multiple times."), 1},
4646
{"xdp-mode", 'x', N_("MODE"), 0, N_("Force XDP attach mode, either skb or native"), 1},
47+
#ifdef MIMIC_USE_LIBXDP
48+
{"use-libxdp", 'X', NULL, 0, N_("Use libxdp instead of libbpf to load XDP program"), 1},
49+
#endif
4750
{"handshake", 'h', N_("i:r"), 0, N_("Controls retry behaviour of initiating connection"), 2},
4851
{"keepalive", 'k', N_("t:i:r:s"), 0, N_("Controls keepalive mechanism"), 2},
4952
{"padding", 'p', N_("bytes"), 0,
@@ -78,6 +81,11 @@ static inline error_t args_parse_opt(int key, char* arg, struct argp_state* stat
7881
case 'x':
7982
args->xdp_mode = try(parse_xdp_mode(arg));
8083
break;
84+
#ifdef MIMIC_USE_LIBXDP
85+
case 'X':
86+
args->use_libxdp = true;
87+
break;
88+
#endif
8189
case 'h':
8290
try(parse_handshake(arg, &args->gsettings.handshake));
8391
break;
@@ -523,31 +531,35 @@ static inline int run_bpf(struct run_args* args, int lock_fd, const char* ifname
523531

524532
// XDP
525533
#ifdef MIMIC_USE_LIBXDP
526-
xdp_ingress = try2_p(xdp_program__from_bpf_obj(skel->obj, "xdp.frags"),
527-
_("failed to create XDP program: %s"), strret);
528-
// libxdp loads the BPF object when attaching.
529-
retcode = xdp_program__attach(xdp_ingress, ifindex, xdp_mode, 0);
530-
if (retcode < 0) {
531-
log_error(_("failed to attach XDP program: %s"), strerror(-retcode));
534+
if (args->use_libxdp) {
535+
xdp_ingress = try2_p(sym_xdp_program__from_bpf_obj(skel->obj, "xdp.frags"),
536+
_("failed to create XDP program: %s"), strret);
537+
// libxdp loads the BPF object when attaching.
538+
retcode = sym_xdp_program__attach(xdp_ingress, ifindex, xdp_mode, 0);
539+
if (retcode < 0) {
540+
log_error(_("failed to attach XDP program: %s"), strerror(-retcode));
532541
#ifdef MIMIC_CHECKSUM_HACK_kfunc
533-
if (retcode == -EINVAL && !is_kmod_loaded())
534-
log_error(_("hint: did you load the Mimic kernel module?"));
542+
if (retcode == -EINVAL && !is_kmod_loaded())
543+
log_error(_("hint: did you load the Mimic kernel module?"));
535544
#endif
536-
cleanup(retcode);
537-
}
538-
#else
539-
retcode = mimic_bpf__load(skel);
540-
if (retcode < 0) {
541-
log_error(_("failed to load BPF program: %s"), strerror(-retcode));
545+
cleanup(retcode);
546+
}
547+
} else
548+
#endif
549+
{
550+
retcode = mimic_bpf__load(skel);
551+
if (retcode < 0) {
552+
log_error(_("failed to load BPF program: %s"), strerror(-retcode));
542553
#ifdef MIMIC_CHECKSUM_HACK_kfunc
543-
if (retcode == -EINVAL && !is_kmod_loaded())
544-
log_error(_("hint: did you load the Mimic kernel module?"));
554+
if (retcode == -EINVAL && !is_kmod_loaded())
555+
log_error(_("hint: did you load the Mimic kernel module?"));
545556
#endif
546-
cleanup(retcode);
557+
cleanup(retcode);
558+
}
559+
try2(
560+
bpf_xdp_attach(ifindex, bpf_program__fd(skel->progs.ingress_handler), args->xdp_mode, NULL),
561+
_("failed to attach XDP program: %s"), strret);
547562
}
548-
try2(bpf_xdp_attach(ifindex, bpf_program__fd(skel->progs.ingress_handler), args->xdp_mode, NULL),
549-
_("failed to attach XDP program: %s"), strret);
550-
#endif
551563
xdp_attached = true;
552564

553565
// TC
@@ -667,11 +679,14 @@ static inline int run_bpf(struct run_args* args, int lock_fd, const char* ifname
667679
sigprocmask(SIG_SETMASK, NULL, NULL);
668680
if (tc_hook_created) tc_hook_cleanup(&tc_hook_egress, &tc_opts_egress);
669681
#ifdef MIMIC_USE_LIBXDP
670-
if (xdp_attached) xdp_program__detach(xdp_ingress, ifindex, xdp_mode, 0);
671-
xdp_program__close(xdp_ingress);
672-
#else
673-
if (xdp_attached) bpf_xdp_detach(ifindex, args->xdp_mode, NULL);
682+
if (args->use_libxdp) {
683+
if (xdp_attached) sym_xdp_program__detach(xdp_ingress, ifindex, xdp_mode, 0);
684+
sym_xdp_program__close(xdp_ingress);
685+
} else
674686
#endif
687+
{
688+
if (xdp_attached) bpf_xdp_detach(ifindex, args->xdp_mode, NULL);
689+
}
675690
if (rb) ring_buffer__free(rb);
676691
if (closure) ffi_closure_free(closure);
677692
if (skel) mimic_bpf__destroy(skel);
@@ -750,7 +765,10 @@ int subcmd_run(struct run_args* args) {
750765

751766
libbpf_set_print(libbpf_print_fn);
752767
#ifdef MIMIC_USE_LIBXDP
753-
libxdp_set_print((libxdp_print_fn_t)libbpf_print_fn);
768+
if (args->use_libxdp) {
769+
dlopen_libxdp();
770+
sym_libxdp_set_print((libxdp_print_fn_t)libbpf_print_fn);
771+
}
754772
#endif
755773
retcode = run_bpf(args, lock_fd, args->ifname, ifindex);
756774
close(lock_fd);

0 commit comments

Comments
 (0)