libxz,
libzstd,
liblz4,
- libbpf,
+ libdl,
libcap,
libblkid,
libmount,
include_directories : includes,
dependencies : [versiondep,
threads,
- libbpf,
+ libdl,
librt,
libseccomp,
libpam,
#if BPF_FRAMEWORK
/* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */
+#include "bpf-dlopen.h"
#include "bpf-link.h"
#include "bpf/socket_bind/socket-bind.skel.h"
#include "bpf/socket_bind/socket-bind-api.bpf.h"
.port_min = item->port_min,
};
- if (bpf_map_update_elem(map_fd, &key, &val, BPF_ANY) != 0)
+ if (sym_bpf_map_update_elem(map_fd, &key, &val, BPF_ANY) != 0)
return -errno;
}
if (!obj)
return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOMEM), "Failed to open BPF object");
- if (bpf_map__resize(obj->maps.sd_bind_allow, MAX(allow_count, 1u)) != 0)
+ if (sym_bpf_map__resize(obj->maps.sd_bind_allow, MAX(allow_count, 1u)) != 0)
return log_unit_error_errno(u, errno,
- "Failed to resize BPF map '%s': %m", bpf_map__name(obj->maps.sd_bind_allow));
+ "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_allow));
- if (bpf_map__resize(obj->maps.sd_bind_deny, MAX(deny_count, 1u)) != 0)
+ if (sym_bpf_map__resize(obj->maps.sd_bind_deny, MAX(deny_count, 1u)) != 0)
return log_unit_error_errno(u, errno,
- "Failed to resize BPF map '%s': %m", bpf_map__name(obj->maps.sd_bind_deny));
+ "Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_deny));
if (socket_bind_bpf__load(obj) != 0)
return log_unit_error_errno(u, errno, "Failed to load BPF object");
- allow_map_fd = bpf_map__fd(obj->maps.sd_bind_allow);
+ allow_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_allow);
assert(allow_map_fd >= 0);
r = update_rules_map(allow_map_fd, allow);
if (r < 0)
return log_unit_error_errno(
u, r, "Failed to put socket bind allow rules into BPF map '%s'",
- bpf_map__name(obj->maps.sd_bind_allow));
+ sym_bpf_map__name(obj->maps.sd_bind_allow));
- deny_map_fd = bpf_map__fd(obj->maps.sd_bind_deny);
+ deny_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_deny);
assert(deny_map_fd >= 0);
r = update_rules_map(deny_map_fd, deny);
if (r < 0)
return log_unit_error_errno(
u, r, "Failed to put socket bind deny rules into BPF map '%s'",
- bpf_map__name(obj->maps.sd_bind_deny));
+ sym_bpf_map__name(obj->maps.sd_bind_deny));
*ret_obj = TAKE_PTR(obj);
return 0;
return 0;
}
- if (!bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, /*ifindex=*/0)) {
+ r = dlopen_bpf();
+ if (r < 0) {
+ log_info_errno(r, "Could not load libbpf: %m");
+ return 0;
+ }
+
+ if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, /*ifindex=*/0)) {
log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"BPF program type cgroup_sock_addr is not supported");
return 0;
return log_unit_error_errno(
u, errno, "Failed to open cgroup=%s for reading", cgroup_path);
- ipv4 = bpf_program__attach_cgroup(obj->progs.sd_bind4, cgroup_fd);
- r = libbpf_get_error(ipv4);
+ ipv4 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind4, cgroup_fd);
+ r = sym_libbpf_get_error(ipv4);
if (r != 0)
return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program",
- bpf_program__name(obj->progs.sd_bind4));
+ sym_bpf_program__name(obj->progs.sd_bind4));
- ipv6 = bpf_program__attach_cgroup(obj->progs.sd_bind6, cgroup_fd);
- r = libbpf_get_error(ipv6);
+ ipv6 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind6, cgroup_fd);
+ r = sym_libbpf_get_error(ipv6);
if (r != 0)
return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program",
- bpf_program__name(obj->progs.sd_bind6));
+ sym_bpf_program__name(obj->progs.sd_bind6));
u->ipv4_socket_bind_link = TAKE_PTR(ipv4);
u->ipv6_socket_bind_link = TAKE_PTR(ipv6);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "dlfcn-util.h"
+#include "bpf-dlopen.h"
+
+#if HAVE_LIBBPF
+static void *bpf_dl = NULL;
+
+struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int);
+long (*sym_libbpf_get_error)(const void *);
+int (*sym_bpf_link__fd)(const struct bpf_link *);
+int (*sym_bpf_link__destroy)(struct bpf_link *);
+int (*sym_bpf_map__fd)(const struct bpf_map *);
+const char* (*sym_bpf_map__name)(const struct bpf_map *);
+int (*sym_bpf_map__resize)(struct bpf_map *, __u32);
+int (*sym_bpf_map_update_elem)(int, const void *, const void *, __u64);
+int (*sym_bpf_object__open_skeleton)(struct bpf_object_skeleton *, const struct bpf_object_open_opts *);
+int (*sym_bpf_object__load_skeleton)(struct bpf_object_skeleton *);
+int (*sym_bpf_object__attach_skeleton)(struct bpf_object_skeleton *);
+void (*sym_bpf_object__detach_skeleton)(struct bpf_object_skeleton *);
+void (*sym_bpf_object__destroy_skeleton)(struct bpf_object_skeleton *);
+bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32);
+const char* (*sym_bpf_program__name)(const struct bpf_program *);
+
+int dlopen_bpf(void) {
+ _cleanup_(dlclosep) void *dl = NULL;
+ int r;
+
+ if (bpf_dl)
+ return 0; /* Already loaded */
+
+ dl = dlopen("libbpf.so.0", RTLD_LAZY);
+ if (!dl)
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "libbpf is not installed: %s", dlerror());
+
+ r = dlsym_many_and_warn(
+ dl,
+ LOG_ERR,
+ DLSYM_ARG(bpf_link__destroy),
+ DLSYM_ARG(bpf_link__fd),
+ DLSYM_ARG(bpf_map__fd),
+ DLSYM_ARG(bpf_map__name),
+ DLSYM_ARG(bpf_map__resize),
+ DLSYM_ARG(bpf_map_update_elem),
+ DLSYM_ARG(bpf_object__open_skeleton),
+ DLSYM_ARG(bpf_object__load_skeleton),
+ DLSYM_ARG(bpf_object__attach_skeleton),
+ DLSYM_ARG(bpf_object__detach_skeleton),
+ DLSYM_ARG(bpf_object__destroy_skeleton),
+ DLSYM_ARG(bpf_probe_prog_type),
+ DLSYM_ARG(bpf_program__attach_cgroup),
+ DLSYM_ARG(bpf_program__name),
+ DLSYM_ARG(libbpf_get_error),
+ NULL);
+ if (r < 0)
+ return r;
+
+ /* Note that we never release the reference here, because there's no real reason to, after all this
+ * was traditionally a regular shared library dependency which lives forever too. */
+ bpf_dl = TAKE_PTR(dl);
+
+ return 1;
+}
+
+#else
+
+int dlopen_bpf(void) {
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "libbpf support is not compiled in.");
+}
+#endif
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#if HAVE_LIBBPF
+
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+
+extern struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int);
+extern long (*sym_libbpf_get_error)(const void *);
+extern int (*sym_bpf_link__fd)(const struct bpf_link *);
+extern int (*sym_bpf_link__destroy)(struct bpf_link *);
+extern int (*sym_bpf_map__fd)(const struct bpf_map *);
+extern const char* (*sym_bpf_map__name)(const struct bpf_map *);
+extern int (*sym_bpf_map__resize)(struct bpf_map *, __u32);
+extern int (*sym_bpf_map_update_elem)(int, const void *, const void *, __u64);
+/* The *_skeleton APIs are autogenerated by bpftool, the targets can be found
+ * in ./build/src/core/bpf/socket_bind/socket-bind.skel.h */
+extern int (*sym_bpf_object__open_skeleton)(struct bpf_object_skeleton *, const struct bpf_object_open_opts *);
+extern int (*sym_bpf_object__load_skeleton)(struct bpf_object_skeleton *);
+extern int (*sym_bpf_object__attach_skeleton)(struct bpf_object_skeleton *);
+extern void (*sym_bpf_object__detach_skeleton)(struct bpf_object_skeleton *);
+extern void (*sym_bpf_object__destroy_skeleton)(struct bpf_object_skeleton *);
+extern bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32);
+extern const char* (*sym_bpf_program__name)(const struct bpf_program *);
+
+#endif
+
+int dlopen_bpf(void);
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include "bpf-dlopen.h"
#include "bpf-link.h"
#include "serialize.h"
bool can_link_bpf_program(struct bpf_program *prog) {
_cleanup_(bpf_link_freep) struct bpf_link *link = NULL;
+ int r;
assert(prog);
+ r = dlopen_bpf();
+ if (r < 0) {
+ log_debug_errno(r, "Could not load libbpf: %m");
+ return false;
+ }
+
/* Pass invalid cgroup fd intentionally. */
- link = bpf_program__attach_cgroup(prog, /*cgroup_fd=*/-1);
+ link = sym_bpf_program__attach_cgroup(prog, /*cgroup_fd=*/-1);
/* EBADF indicates that bpf_link is supported by kernel. */
- return libbpf_get_error(link) == -EBADF;
+ return sym_libbpf_get_error(link) == -EBADF;
}
int serialize_bpf_link(FILE *f, FDSet *fds, const char *key, struct bpf_link *link) {
if (!link)
return -ENOENT;
- if (libbpf_get_error(link) != 0)
+ if (sym_libbpf_get_error(link) != 0)
return -EINVAL;
- fd = bpf_link__fd(link);
+ fd = sym_bpf_link__fd(link);
return serialize_fd(f, fds, key, fd);
}
struct bpf_link *bpf_link_free(struct bpf_link *link) {
- /* bpf_link__destroy handles link == NULL case */
- (void) bpf_link__destroy(link);
+ /* Avoid a useless dlopen() if link == NULL */
+ if (!link)
+ return NULL;
+
+ (void) sym_bpf_link__destroy(link);
return NULL;
}
boot-timestamps.h
bootspec.c
bootspec.h
+ bpf-dlopen.c
+ bpf-dlopen.h
bpf-program.c
bpf-program.h
bridge-util.c
libshared_deps = [threads,
libacl,
libblkid,
- libbpf,
libcap,
libcrypt,
+ libdl,
libgcrypt,
libiptc,
libkmod,
[['src/test/test-socket-bind.c'],
[libcore,
libshared],
- [libbpf],
+ [libdl],
core_includes,
'BPF_FRAMEWORK'],
]
#include <dlfcn.h>
#include <stdlib.h>
+#include "bpf-dlopen.h"
#include "cryptsetup-util.h"
#include "idn-util.h"
#include "libfido2-util.h"
assert_se(dlopen_libfido2() >= 0);
#endif
+#if HAVE_LIBBPF
+ assert_se(dlopen_bpf() >= 0);
+#endif
+
return 0;
}
local lib path
# A number of dependencies is now optional via dlopen, so the install
# script will not pick them up, since it looks at linkage.
- for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu libfido2; do
+ for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu libfido2 libbpf; do
ddebug "Searching for $lib via pkg-config"
if pkg-config --exists "$lib"; then
path="$(pkg-config --variable=libdir "$lib")"
import argparse
import logging
import pathlib
+import re
import subprocess
import sys
logging.debug('Generating BPF skeleton:')
logging.debug('{}'.format(' '.join(bpftool_args)))
- subprocess.check_call(bpftool_args, stdout=out_fd)
+ skel = subprocess.check_output(bpftool_args, universal_newlines=True)
+ # libbpf is used via dlopen(), so rename symbols as defined
+ # in src/shared/bpf-dlopen.h
+ skel = re.sub(r'(bpf_object__\w+_skeleton)', r'sym_\1', skel)
+ out_fd.write(skel)
def bpf_build(args):