diff --git a/meson.build b/meson.build index 519de53345..2115e7f991 100644 --- a/meson.build +++ b/meson.build @@ -1008,11 +1008,9 @@ else # We check for 'bpftool' first, honouring $PATH, and in /usr/sbin/ for Debian. bpftool = find_program('bpftool', '/usr/sbin/bpftool', required : bpf_framework_required) - bpf_arches = ['x86_64'] deps_found = libbpf.found() and clang.found() and llvm_strip.found() and bpftool.found() # Can build BPF program from source code in restricted C - conf.set10('BPF_FRAMEWORK', - bpf_arches.contains(host_machine.cpu_family()) and deps_found) + conf.set10('BPF_FRAMEWORK', deps_found) endif libmount = dependency('mount', @@ -1685,7 +1683,6 @@ subdir('src/boot/efi') ############################################################ -build_bpf_skel_py = find_program('tools/build-bpf-skel.py') generate_gperfs = find_program('tools/generate-gperfs.py') make_autosuspend_rules_py = find_program('tools/make-autosuspend-rules.py') make_directive_index_py = find_program('tools/make-directive-index.py') diff --git a/src/core/bpf-socket-bind.c b/src/core/bpf-socket-bind.c index e9c0a2f9bd..c5176aa481 100644 --- a/src/core/bpf-socket-bind.c +++ b/src/core/bpf-socket-bind.c @@ -11,7 +11,7 @@ /* 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-skel.h" #include "bpf/socket_bind/socket-bind-api.bpf.h" static struct socket_bind_bpf *socket_bind_bpf_free(struct socket_bind_bpf *obj) { diff --git a/src/core/bpf/meson.build b/src/core/bpf/meson.build new file mode 100644 index 0000000000..ab1a7167a6 --- /dev/null +++ b/src/core/bpf/meson.build @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: LGPL-2.1+ + +if conf.get('BPF_FRAMEWORK') == 1 + clang_flags = [ + '-Wno-compare-distinct-pointer-types', + '-O2', + '-target', + 'bpf', + '-g', + '-c', + ] + + clang_arch_flag = '-D__@0@__'.format(host_machine.cpu_family()) + + if meson.version().version_compare('>= 0.58') + libbpf_include_dir = libbpf.get_variable('includedir') + else + libbpf_include_dir = libbpf.get_variable(pkgconfig : 'includedir') + endif + + bpf_o_unstripped_cmd = [ + clang, + clang_flags, + clang_arch_flag, + '-I.' + ] + + if not meson.is_cross_build() + target_triplet_cmd = run_command('gcc', '-dumpmachine', check: false) + if target_triplet_cmd.returncode() == 0 + target_triplet = target_triplet_cmd.stdout().strip() + bpf_o_unstripped_cmd += [ + '-isystem', + '/usr/include/@0@'.format(target_triplet) + ] + endif + endif + + bpf_o_unstripped_cmd += [ + '-idirafter', + libbpf_include_dir, + '@INPUT@', + '-o', + '@OUTPUT@' + ] + + bpf_o_cmd = [ + llvm_strip, + '-g', + '@INPUT@', + '-o', + '@OUTPUT@' + ] + + skel_h_cmd = [ + bpftool, + 'g', + 's', + '@INPUT@' + ] +endif diff --git a/src/core/bpf/restrict_fs/meson.build b/src/core/bpf/restrict_fs/meson.build index c92cccae26..dfe3f12033 100644 --- a/src/core/bpf/restrict_fs/meson.build +++ b/src/core/bpf/restrict_fs/meson.build @@ -1,14 +1,22 @@ # SPDX-License-Identifier: LGPL-2.1-or-later if conf.get('BPF_FRAMEWORK') == 1 - restrict_fs_skel_h = custom_target( - 'restrict-fs-skel.h', + restrict_fs_bpf_o_unstripped = custom_target( + 'restrict-fs.bpf.unstripped.o', input : 'restrict-fs.bpf.c', - output : 'restrict-fs-skel.h', - command : [build_bpf_skel_py, - '--clang_exec', clang.path(), - '--llvm_strip_exec', llvm_strip.path(), - '--bpftool_exec', bpftool.path(), - '--arch', host_machine.cpu_family(), - '@INPUT@', '@OUTPUT@']) + output : 'restrict-fs.bpf.unstripped.o', + command : bpf_o_unstripped_cmd) + + restrict_fs_bpf_o = custom_target( + 'restrict-fs.bpf.o', + input : restrict_fs_bpf_o_unstripped, + output : 'restrict-fs.bpf.o', + command : bpf_o_cmd) + + restrict_fs_skel_h = custom_target( + 'restrict-fs.skel.h', + input : restrict_fs_bpf_o, + output : 'restrict-fs.skel.h', + command : skel_h_cmd, + capture : true) endif diff --git a/src/core/bpf/restrict_fs/restrict-fs-skel.h b/src/core/bpf/restrict_fs/restrict-fs-skel.h new file mode 100644 index 0000000000..412cf62eda --- /dev/null +++ b/src/core/bpf/restrict_fs/restrict-fs-skel.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/* The SPDX header above is actually correct in claiming this was + * LGPL-2.1-or-later, because it is. Since the kernel doesn't consider that + * compatible with GPL we will claim this to be GPL however, which should be + * fine given that LGPL-2.1-or-later downgrades to GPL if needed. + */ + +/* libbpf is used via dlopen(), so rename symbols */ +#define bpf_object__open_skeleton sym_bpf_object__open_skeleton +#define bpf_object__load_skeleton sym_bpf_object__load_skeleton +#define bpf_object__destroy_skeleton sym_bpf_object__destroy_skeleton + +#include "bpf/restrict_fs/restrict-fs.skel.h" diff --git a/src/core/bpf/restrict_ifaces/meson.build b/src/core/bpf/restrict_ifaces/meson.build index 38f7dbbd51..b7e2bc1519 100644 --- a/src/core/bpf/restrict_ifaces/meson.build +++ b/src/core/bpf/restrict_ifaces/meson.build @@ -1,14 +1,22 @@ # SPDX-License-Identifier: LGPL-2.1-or-later if conf.get('BPF_FRAMEWORK') == 1 + restrict_ifaces_bpf_o_unstripped = custom_target( + 'restrict-ifaces.bpf.unstripped.o', + input : 'restrict-ifaces.bpf.c', + output : 'restrict-ifaces.bpf.unstripped.o', + command : bpf_o_unstripped_cmd) + + restrict_ifaces_bpf_o = custom_target( + 'restrict-ifaces.bpf.o', + input : restrict_ifaces_bpf_o_unstripped, + output : 'restrict-ifaces.bpf.o', + command : bpf_o_cmd) + restrict_ifaces_skel_h = custom_target( 'restrict-ifaces.skel.h', - input : 'restrict-ifaces.bpf.c', + input : restrict_ifaces_bpf_o, output : 'restrict-ifaces.skel.h', - command : [build_bpf_skel_py, - '--clang_exec', clang.path(), - '--llvm_strip_exec', llvm_strip.path(), - '--bpftool_exec', bpftool.path(), - '--arch', host_machine.cpu_family(), - '@INPUT@', '@OUTPUT@']) + command : skel_h_cmd, + capture : true) endif diff --git a/src/core/bpf/restrict_ifaces/restrict-ifaces-skel.h b/src/core/bpf/restrict_ifaces/restrict-ifaces-skel.h new file mode 100644 index 0000000000..f937490954 --- /dev/null +++ b/src/core/bpf/restrict_ifaces/restrict-ifaces-skel.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/* The SPDX header above is actually correct in claiming this was + * LGPL-2.1-or-later, because it is. Since the kernel doesn't consider that + * compatible with GPL we will claim this to be GPL however, which should be + * fine given that LGPL-2.1-or-later downgrades to GPL if needed. + */ + +/* libbpf is used via dlopen(), so rename symbols */ +#define bpf_object__open_skeleton sym_bpf_object__open_skeleton +#define bpf_object__load_skeleton sym_bpf_object__load_skeleton +#define bpf_object__destroy_skeleton sym_bpf_object__destroy_skeleton + +#include "bpf/restrict_ifaces/restrict-ifaces.skel.h" diff --git a/src/core/bpf/socket_bind/meson.build b/src/core/bpf/socket_bind/meson.build index f5cfc04b00..8211a7a5c9 100644 --- a/src/core/bpf/socket_bind/meson.build +++ b/src/core/bpf/socket_bind/meson.build @@ -1,14 +1,22 @@ # SPDX-License-Identifier: LGPL-2.1-or-later if conf.get('BPF_FRAMEWORK') == 1 + socket_bind_bpf_o_unstripped = custom_target( + 'socket-bind.bpf.unstripped.o', + input : 'socket-bind.bpf.c', + output : 'socket-bind.bpf.unstripped.o', + command : bpf_o_unstripped_cmd) + + socket_bind_bpf_o = custom_target( + 'socket-bind.bpf.o', + input : socket_bind_bpf_o_unstripped, + output : 'socket-bind.bpf.o', + command : bpf_o_cmd) + socket_bind_skel_h = custom_target( 'socket-bind.skel.h', - input : 'socket-bind.bpf.c', + input : socket_bind_bpf_o, output : 'socket-bind.skel.h', - command : [build_bpf_skel_py, - '--clang_exec', clang.path(), - '--llvm_strip_exec', llvm_strip.path(), - '--bpftool_exec', bpftool.path(), - '--arch', host_machine.cpu_family(), - '@INPUT@', '@OUTPUT@']) + command : skel_h_cmd, + capture : true) endif diff --git a/src/core/bpf/socket_bind/socket-bind-skel.h b/src/core/bpf/socket_bind/socket-bind-skel.h new file mode 100644 index 0000000000..e0d16269cd --- /dev/null +++ b/src/core/bpf/socket_bind/socket-bind-skel.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/* The SPDX header above is actually correct in claiming this was + * LGPL-2.1-or-later, because it is. Since the kernel doesn't consider that + * compatible with GPL we will claim this to be GPL however, which should be + * fine given that LGPL-2.1-or-later downgrades to GPL if needed. + */ + +/* libbpf is used via dlopen(), so rename symbols */ +#define bpf_object__open_skeleton sym_bpf_object__open_skeleton +#define bpf_object__load_skeleton sym_bpf_object__load_skeleton +#define bpf_object__destroy_skeleton sym_bpf_object__destroy_skeleton + +#include "bpf/socket_bind/socket-bind.skel.h" diff --git a/src/core/meson.build b/src/core/meson.build index c02543bd06..92a811f2f0 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -133,6 +133,8 @@ libcore_sources = ''' unit.h '''.split() +subdir('bpf') + subdir('bpf/socket_bind') if conf.get('BPF_FRAMEWORK') == 1 libcore_sources += [socket_bind_skel_h] diff --git a/src/core/restrict-ifaces.c b/src/core/restrict-ifaces.c index a17c5d2bf7..7650031434 100644 --- a/src/core/restrict-ifaces.c +++ b/src/core/restrict-ifaces.c @@ -10,7 +10,7 @@ #include "bpf-dlopen.h" #include "bpf-link.h" -#include "bpf/restrict_ifaces/restrict-ifaces.skel.h" +#include "bpf/restrict_ifaces/restrict-ifaces-skel.h" static struct restrict_ifaces_bpf *restrict_ifaces_bpf_free(struct restrict_ifaces_bpf *obj) { restrict_ifaces_bpf__destroy(obj); diff --git a/tools/build-bpf-skel.py b/tools/build-bpf-skel.py deleted file mode 100755 index 0752174611..0000000000 --- a/tools/build-bpf-skel.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: LGPL-2.1-or-later - -import argparse -import logging -import pathlib -import re -import subprocess -import sys - -def clang_arch_flag(arch): - return '-D__{}__'.format(arch) - - -def target_triplet(): - gcc_exec = 'gcc' - - try: - return subprocess.check_output([gcc_exec, '-dumpmachine'], - universal_newlines=True).strip() - except subprocess.CalledProcessError as e: - logging.error('Failed to get target triplet: {}'.format(e)) - except FileNotFoundError: - logging.error('gcc not installed') - return None - - -def clang_compile(clang_exec, clang_flags, src_c, out_file, target_arch, - target_triplet): - clang_args = [clang_exec, *clang_flags, target_arch, '-I.'] - - if target_triplet: - clang_args += [ - '-isystem', - '/usr/include/{}'.format(target_triplet)] - - clang_args += [ - '-idirafter', - '/usr/local/include', - '-idirafter', - '/usr/include'] - - clang_args += [src_c, '-o', out_file] - - logging.debug('{}'.format(' '.join(clang_args))) - subprocess.check_call(clang_args) - - -def llvm_strip(llvm_strip_exec, in_file): - llvm_strip_args = [llvm_strip_exec, '-g', in_file] - - logging.debug('Stripping useless DWARF info:') - logging.debug('{}'.format(' '.join(llvm_strip_args))) - - subprocess.check_call(llvm_strip_args) - - -def gen_bpf_skeleton(bpftool_exec, in_file, out_fd): - bpftool_args = [bpftool_exec, 'g', 's', in_file] - - logging.debug('Generating BPF skeleton:') - logging.debug('{}'.format(' '.join(bpftool_args))) - 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): - clang_flags = [ - '-Wno-compare-distinct-pointer-types', - '-O2', - '-target', - 'bpf', - '-g', - '-c', - ] - - clang_out_path = pathlib.Path(args.bpf_src_c).with_suffix('.o') - with clang_out_path.open(mode='w') as clang_out, \ - open(args.bpf_skel_h, mode='w') as bpf_skel_h: - clang_compile(clang_exec=args.clang_exec, - clang_flags=clang_flags, - src_c=args.bpf_src_c, - out_file=clang_out.name, - target_arch=clang_arch_flag(args.arch), - target_triplet=target_triplet()) - - llvm_strip(llvm_strip_exec=args.llvm_strip_exec, in_file=clang_out.name) - - gen_bpf_skeleton(bpftool_exec=args.bpftool_exec, - in_file=clang_out.name, - out_fd=bpf_skel_h) - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - - parser.add_argument( - 'bpf_src_c', - help='Path to *.c source of BPF program in systemd source tree \ - relative to the work directory') - - parser.add_argument( - 'bpf_skel_h', - help='Path to C header file') - - parser.add_argument( - '--clang_exec', - help='Path to clang exec') - - parser.add_argument( - '--llvm_strip_exec', - help='Path to llvm-strip exec') - - parser.add_argument( - '--bpftool_exec', - help='Path to bpftool exec') - - parser.add_argument( - '--arch', - help='Target CPU architecture', - default='x86_64') - - args = parser.parse_args(); - - logging.basicConfig(stream=sys.stderr, level=logging.WARNING) - bpf_build(args)