Skip to content

Conversation

@jkartseva
Copy link

An attempt to replace direct bpf syscalls with libbpf was made in #12151 where libbpf was introduced as a git submodule.
This is another approach with libbpf as a library.
libbpf package build from GH mirror is available in Fedora [1].
Debian package exists as well but it is build from kernel sources [2].
There is no CentOS package but it's possible to make one by rebuild the Fedora package and publishing it to EPEL repo.
I expect initial test failures, because they may lack of libbpf package installed thus libbpf dependency unresolved.

[1] https://rpms.remirepo.net/rpmphp/zoom.php?rpm=libbpf
[2] https://packages.debian.org/sid/libbpf-dev

@anitazha anitazha added the bpf label Oct 8, 2019
@jkartseva jkartseva force-pushed the use-libbpf branch 2 times, most recently from 417bd6f to 5bad0d6 Compare October 8, 2019 22:10
@jkartseva
Copy link
Author

jkartseva commented Oct 9, 2019

In order to push this forward, some help from the community is needed, so I'm tagging people :)
List of blockers:

  1. Testing ecosystem needs to support libbpf dependency. There is no CentOS package yet but publishing it to Fedora EPEL seems to be a promising approach. cc @evverx
    Evgeny, how hard it's to modify CentOS CI tests after libbpf is available there?
  2. Secondary, we have Debian built from the kernel sources. We need to switch it to GH mirror. cc @rfc1036
    Marco, I wonder how hard it is to file a bugreport similar to what's made in Fedora? [1]
  3. Absence of libbpf in Ubuntu
  4. After a package is available in Debian and Ubuntu, libbpf should be made systemd dependency, so it can be installed by sudo apt-get build-dep systemd -y command. This should help with systemd.systemd test.
  5. There are also tests dependent on [2]: ubuntu bionic tests and SemaphoreCI cc @martinpitt

So, a general question: let's pretend libbpf package is available on all relevant platforms, what are the steps to introduce it as a dependency to systemd and testing infra? How new package dependencies are usually added? cc @keszybz @mrc0mmand @poettering

As an alternative, I don't mind reviving submodule approach #12151 but it also needs support from testing infra so ubuntu bionic tests are unblocked.

Thanks for all you replies!

[1] https://lore.kernel.org/netdev/A273A3DB-C63E-488F-BB0C-B7B2AB6D99BE@fb.com/
[2] https://salsa.debian.org/systemd-team/systemd

@evverx
Copy link
Contributor

evverx commented Oct 9, 2019

@wat-ze-hex regarding CentOS CI, I believe libbpf can be added to https://github.com/systemd/systemd-centos-ci/blob/master/agent/bootstrap.sh#L45-L50 (where as far as I know, all the dependencies are installed). Generally @mrc0mmand maintains those scripts and knows what to do much better than me.

Regarding systemd.systemd, there the fuzzers are built and we generally skip all the dependencies so, by analogy with libseccomp, something like

want_libbpf = get_option('libbpf')
if want_libbpf != 'false' and not skip_deps
   ...

should make that part green.

@evverx
Copy link
Contributor

evverx commented Oct 10, 2019

I've just realized that libbpf isn't supposed to be optional so skipping it when the fuzzers are built doesn't look right. To some extent we kind of get away with it (with libmount and libcap) because those libraries are also built with all the sanitizers from scratch on the OSS-Fuzz side but I'm not sure how hard it will be to bring libbpf there. Ideally we should build dependencies like that along with systemd and link them statically (which will automatically resolve #11730 and #12608) but nobody has got round to it yet. Let's just ignore systemd.systemd for now.

@jkartseva
Copy link
Author

@evverx Just to clarify, do you mean fuzzit.sh script triggered by TravisCI and triggering test/fuzz/test-.* it its turn? My thought it is failing because libbpf package doesn't present in Ubuntu.
Yes, it's impossible to make libbpf optional.

@evverx
Copy link
Contributor

evverx commented Oct 10, 2019

@wat-ze-hex I was talking about fuzzbuzz.sh, which among other things builds the fuzzers we run on OSS-Fuzz.

fuzzit.sh compiles the fuzzers as well and send them to Fuzzit, which we use for regression testing. It's true currently it's failing because it can't find libbpf on Ubuntu but even if libbpf was on Travis CI the fuzzers would fail because Travis CI is just a build environment and whatever we install there isn't available in the runtime environment. The same is applicable to OSS-Fuzz where the build environment (where it will be relatively easy to install libbpf once it's brought to Ubuntu) is different from the runtime environment (where build dependencies usually aren't available).

@evverx
Copy link
Contributor

evverx commented Oct 10, 2019

@wat-ze-hex I think what I was trying to say is documented in https://github.com/google/oss-fuzz/blob/97060c44dec9c25b8c74a4ee05a217bd68f119fe/docs/further-reading/fuzzer_environment.md#runtime-dependencies.

When the fuzzers were introduced we kind of ignored that, made some assumptions about the runtime environment and somehow convinced the OSS-Fuzz team to add an undocumented feature allowing us to also use libshared-systemd linked dynamically. Generally it was a stopgap to get the fuzzers up and running and the whole thing can actually break any moment. Everybody else links their dependencies statically.

Ideally, we should fix the fuzzers but if it takes too long another option would be to use my YOLO approach from #12608 where both libcap and libmount were skipped when the fuzzers were built (which is, well, more or less OK because for the fuzzers those dependencies are technically optional).

Anyway, I don't think at this point it's important enough. I'm pretty sure we'll figure something out eventually. My understanding is that it would be better to decide where the PR is headed in general. I hope it makes sense.

@mrc0mmand
Copy link
Member

@wat-ze-hex as for the CentOS 7 job, I could rebuild the libbpf package and import it into our systemd CentOS CI copr repo until it's available in EPEL (if it's going to be available there). Not sure about the Arch Linux part of CentOS CI, though, as I have absolutely zero experience building packages there.

Copy link
Member

@keszybz keszybz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain what is happening and why... Some things look suspicious, but without comments it's hard to understand why they are done this way.

@jkartseva
Copy link
Author

jkartseva commented Oct 10, 2019

@evverx

@wat-ze-hex I think what I was trying to say is documented in https://github.com/google/oss-fuzz/blob/97060c44dec9c25b8c74a4ee05a217bd68f119fe/docs/further-reading/fuzzer_environment.md#runtime-dependencies.

I see that runtime dependency is a concern. What about libbpf linked statically, i.e.:

libbpf = dependency('libbpf', required : false, static : true)

In the case of static linking there is still a question of how to link the dependencies of libbpf – libelf and zlib. If we can rely on their presence in runtime environments, they can be linked dynamically. If we can't, we need to link libz.a and libelf.a.
Wdyt?

@jkartseva
Copy link
Author

@wat-ze-hex as for the CentOS 7 job, I could rebuild the libbpf package and import it into our systemd CentOS CI copr repo until it's available in EPEL (if it's going to be available there). Not sure about the Arch Linux part of CentOS CI, though, as I have absolutely zero experience building packages there.

That would be very helpful, thank you! As for EPEL packaging it's WIP, the conversation can be tracked in [1]
Fedora package is in [2]

[1] https://lore.kernel.org/netdev/20191008073958.GA10009@krava/
[2] https://apps.fedoraproject.org/packages/libbpf

@mbiebl
Copy link
Contributor

mbiebl commented Oct 10, 2019

fwiw, I think it's way too early to add a dependency on libbpf.
This should only happen once libbpf has seen more widespread usage and is available in (most) distros, ideally LTS distros.

@evverx
Copy link
Contributor

evverx commented Oct 11, 2019

If we can rely on their presence in runtime environments, they can be linked dynamically. If we can't, we need to link libz.a and libelf.a

I'll have to find out whether these are available there. Though, I was told (repeatedly) not to rely on anything. What I'm concerned about is that even if they are there it's going to be another stopgap we'll never fix (or, more precisely, the part linking libbpf will be correct but the rest will be the way it is) :-)

This should only happen once libbpf has seen more widespread usage

@mbiebl Given that some (probably most) projects heavily relying on BPF (most notably https://github.com/iovisor/bcc) have already switched to libbpf (as a submodule usually) I'd say the library is as widespread as it can possibly be (considering the nature of the library). If that's not enough, I don't know what is. Plus, as far as I can tell, it's already tested automatically better than a lot of other open source projects that have seen widespread usage and nevertheless are failing to compile with -Wall -Wextra. (systemd also fails to compile with -Wall -Wextra but that doesn't count obviously :-))

@boucman
Copy link
Contributor

boucman commented Oct 11, 2019

Well, I did a quick search and bcc seems to be supported neither in yocto nor buildroot afaict (there are some patches under buildroot, but they are still under consideration). I couldn't find libbpf either, but I didn't dig that deep.

This is usually a strong sign that those libraries do not support cross-compilation which is essential for the embedded world. So... this would probably block any systemd upgrade in the embedded world, which is bad. especially if it's a mandatory dependency.

@evverx
Copy link
Contributor

evverx commented Oct 11, 2019

This is usually a strong sign that those libraries do not support cross-compilation which is essential for the embedded world.

@boucman have you tried to cross-compile it? If it doesn't work, it's possible to open an issue on their bug tracker at https://github.com/libbpf/libbpf. All issues I opened there were closed in less than a week so in my experience the project is very responsive. I'd also like to point out that systemd itself, as you might have noticed, have some issues with cross-compilation from time to time and relies on bug reports and patches from people who care about it.

@evverx
Copy link
Contributor

evverx commented Oct 11, 2019

especially if it's a mandatory dependency.

I'm not sure if it was discussed at All Systems Go but given that it's going to be a normal dependency (as opposed to a manually implemented part of systemd), it seems it would make sense to make it possible to make it optional like almost everything else. Another option would be to keep using the old stuff if the library isn't available (so that the BPF part of systemd won't stop working suddenly) effectively cementing the status quo where libbpf won't be seen in the foreseeable future but without any updates and bug fixes. New features and bug fixes would be present in the maintained "libbpf" part only and if those features and bug fixes are important enough for, for example, embedded folks they would find to a way to bring libbpf there.

@jkartseva
Copy link
Author

jkartseva commented Oct 11, 2019

@mbiebl

fwiw, I think it's way too early to add a dependency on libbpf.
This should only happen once libbpf has seen more widespread usage and is available in (most) distros, ideally LTS distros.

That's a chicken and egg problem: packages don't pop up by themselves unless driven by a use case, a use case is blocked by absence of packages. systemd is a perfect example of a use case because the present systemd BPF infra... well... sucks.
So we can wait until someone do a dirty job for us, or we can drive it. The problem with wait is that ETA is unpredictable and in the worst case infinite.
I'm flexible and can go back to submodule approach #12151 as a compromise until more distos have a package.

@mrc0mmand
Copy link
Member

mrc0mmand commented Oct 11, 2019

@wat-ze-hex as for the CentOS 7 job, I could rebuild the libbpf package and import it into our systemd CentOS CI copr repo until it's available in EPEL (if it's going to be available there). Not sure about the Arch Linux part of CentOS CI, though, as I have absolutely zero experience building packages there.

That would be very helpful, thank you! As for EPEL packaging it's WIP, the conversation can be tracked in [1]
Fedora package is in [2]

[1] https://lore.kernel.org/netdev/20191008073958.GA10009@krava/
[2] https://apps.fedoraproject.org/packages/libbpf

The COPR EPEL7 build is pending, shouldn't take much longer. fedpkg --relese epel7 mockbuild passed without an issue, so it should be a matter of simply adding a new dependency in the CentOS 7 job once the package is built.

As for the Arch Linux jobs, I guess I'll finally have to learn how to use AUR, so we can test it there as well.

@mrc0mmand
Copy link
Member

@wat-ze-hex the CentOS 7 job finally got past the meson setup phase:

Run-time dependency libbpf found: YES 0.0.5

@mrc0mmand
Copy link
Member

@wat-ze-hex as for Arch Linux - I wrote a simple PKGBUILD file (inspired by the respective Fedora SPEC) and it seems to be working as intended:

# sudo -u builder makepkg
==> Making package: libbpf 0.0.5-1 (Fri 11 Oct 2019 08:38:18 PM UTC)
==> Checking runtime dependencies...
==> Checking buildtime dependencies...
==> Retrieving sources...
  -> Downloading v0.0.5.tar.gz...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   121    0   121    0     0    384      0 --:--:-- --:--:-- --:--:--   384
100  156k    0  156k    0     0   139k      0 --:--:--  0:00:01 --:--:--  200k
==> Validating source files with md5sums...
    v0.0.5.tar.gz ... Skipped
==> Extracting sources...
  -> Extracting v0.0.5.tar.gz with bsdtar
==> Starting build()...
mkdir -p ./staticobjs
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c bpf.c -o staticobjs/bpf.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c btf.c -o staticobjs/btf.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c libbpf.c -o staticobjs/libbpf.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c libbpf_errno.c -o staticobjs/libbpf_errno.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c netlink.c -o staticobjs/netlink.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c nlattr.c -o staticobjs/nlattr.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c str_error.c -o staticobjs/str_error.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c libbpf_probes.c -o staticobjs/libbpf_probes.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c bpf_prog_linfo.c -o staticobjs/bpf_prog_linfo.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c xsk.c -o staticobjs/xsk.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c btf_dump.c -o staticobjs/btf_dump.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -D_FORTIFY_SOURCE=2 -c hashmap.c -o staticobjs/hashmap.o
ar rcs libbpf.a staticobjs/bpf.o staticobjs/btf.o staticobjs/libbpf.o staticobjs/libbpf_errno.o staticobjs/netlink.o staticobjs/nlattr.o staticobjs/str_error.o staticobjs/libbpf_probes.o staticobjs/bpf_prog_linfo.o staticobjs/xsk.o staticobjs/btf_dump.o staticobjs/hashmap.o
mkdir -p ./sharedobjs
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c bpf.c -o sharedobjs/bpf.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c btf.c -o sharedobjs/btf.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c libbpf.c -o sharedobjs/libbpf.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c libbpf_errno.c -o sharedobjs/libbpf_errno.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c netlink.c -o sharedobjs/netlink.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c nlattr.c -o sharedobjs/nlattr.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c str_error.c -o sharedobjs/str_error.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c libbpf_probes.c -o sharedobjs/libbpf_probes.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c bpf_prog_linfo.c -o sharedobjs/bpf_prog_linfo.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c xsk.c -o sharedobjs/xsk.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c btf_dump.c -o sharedobjs/btf_dump.o
cc -I. -I../include -I../include/uapi -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fPIC -fvisibility=hidden -DSHARED -D_FORTIFY_SOURCE=2 -c hashmap.c -o sharedobjs/hashmap.o
cc -shared -Wl,--version-script=libbpf.map \
	      -Wl,-soname,libbpf.so.0 \
	      sharedobjs/bpf.o sharedobjs/btf.o sharedobjs/libbpf.o sharedobjs/libbpf_errno.o sharedobjs/netlink.o sharedobjs/nlattr.o sharedobjs/str_error.o sharedobjs/libbpf_probes.o sharedobjs/bpf_prog_linfo.o sharedobjs/xsk.o sharedobjs/btf_dump.o sharedobjs/hashmap.o -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -lelf -o libbpf.so.0.0.5
ln -sf libbpf.so.0.0.5 libbpf.so.0
ln -sf libbpf.so.0 libbpf.so
sed -e "s|@PREFIX@|/usr|" \
	-e "s|@LIBDIR@|/usr/lib64|" \
	-e "s|@VERSION@|0.0.5|" \
	< libbpf.pc.template > libbpf.pc
==> Entering fakeroot environment...
==> Starting package()...
if [ ! -d '/workspace/pkg/libbpf//usr/include/bpf' ]; then install -d -m 755 '/workspace/pkg/libbpf//usr/include/bpf'; fi; install bpf.h libbpf.h btf.h xsk.h libbpf_util.h -m 644 '/workspace/pkg/libbpf//usr/include/bpf'
if [ ! -d '/workspace/pkg/libbpf//usr/lib64/pkgconfig' ]; then install -d -m 755 '/workspace/pkg/libbpf//usr/lib64/pkgconfig'; fi; install ./libbpf.pc -m 644 '/workspace/pkg/libbpf//usr/lib64/pkgconfig'
if [ ! -d '/workspace/pkg/libbpf//usr/lib64' ]; then install -d -m 755 '/workspace/pkg/libbpf//usr/lib64'; fi; cp -fpR ./libbpf.a ./libbpf.so ./libbpf.so.0 ./libbpf.so.0.0.5 '/workspace/pkg/libbpf//usr/lib64'
==> Tidying install...
  -> Removing libtool files...
  -> Purging unwanted files...
  -> Stripping unneeded symbols from binaries and libraries...
  -> Compressing man and info pages...
==> Checking for packaging issues...
==> Creating package "libbpf"...
  -> Generating .PKGINFO file...
  -> Generating .BUILDINFO file...
  -> Generating .MTREE file...
  -> Compressing package...
==> Leaving fakeroot environment.
==> Finished making: libbpf 0.0.5-1 (Fri 11 Oct 2019 08:38:28 PM UTC)
# tar tvf libbpf-0.0.5-1-x86_64.pkg.tar.xz 
-rw-r--r-- root/root       403 2019-10-11 20:38 .PKGINFO
-rw-r--r-- root/root      5030 2019-10-11 20:38 .BUILDINFO
-rw-r--r-- root/root       930 2019-10-11 20:38 .MTREE
drwxr-xr-x root/root         0 2019-10-11 20:38 usr/
drwxr-xr-x root/root         0 2019-10-11 20:38 usr/include/
drwxr-xr-x root/root         0 2019-10-11 20:38 usr/include/bpf/
-rw-r--r-- root/root      6416 2019-10-11 20:38 usr/include/bpf/bpf.h
-rw-r--r-- root/root      8195 2019-10-11 20:38 usr/include/bpf/btf.h
-rw-r--r-- root/root     19867 2019-10-11 20:38 usr/include/bpf/libbpf.h
-rw-r--r-- root/root      1643 2019-10-11 20:38 usr/include/bpf/libbpf_util.h
-rw-r--r-- root/root      6289 2019-10-11 20:38 usr/include/bpf/xsk.h
drwxr-xr-x root/root         0 2019-10-11 20:38 usr/lib64/
-rw-r--r-- root/root    226596 2019-10-11 20:38 usr/lib64/libbpf.a
lrwxrwxrwx root/root         0 2019-10-11 20:38 usr/lib64/libbpf.so -> libbpf.so.0
lrwxrwxrwx root/root         0 2019-10-11 20:38 usr/lib64/libbpf.so.0 -> libbpf.so.0.0.5
-rwxr-xr-x root/root    141216 2019-10-11 20:38 usr/lib64/libbpf.so.0.0.5
drwxr-xr-x root/root         0 2019-10-11 20:38 usr/lib64/pkgconfig/
-rw-r--r-- root/root       241 2019-10-11 20:38 usr/lib64/pkgconfig/libbpf.pc

Is it worth pushing into the Arch User Repository (AUR) or you already have plans to do it yourself (either to AUR or core)?

@jkartseva
Copy link
Author

jkartseva commented Oct 14, 2019

@evverx

Another option would be to keep using the old stuff if the library isn't available (so that the BPF part of systemd won't stop working suddenly) effectively cementing the status quo where libbpf won't be seen in the foreseeable future but without any updates and bug fixes.

  1. This still means two things to maintain. No new features for old infra sound fine, but no maintenance at all (e.g. no bug fixes) for functionality which does something useful sounds unrealistic.
    Minor note regarding no features: I have PR bpf: extend bpf cgroup program support #13496 which, if merged, violates your proposal :)
  2. A user will have to keep in mind e.g. which unit file option invokes BPF infra v. 1 and which v. 2. That can be confusing.
  3. In the ideal world the infra part may be static but same can't be applied for BPF programs – firewall and devices. Presence of both v. 1 and v. 2 implies that there will be two versions of programs so things are complicated even more. Poor user.
  4. Will there be End-of-Life for v. 1? It can't be there forever, isn't it?
  5. Presence of the old stuff slows down evolvement of new stuff due to less feature request, bug reports and on-boarding experience.
  6. Overhead for implementing, maintaining and deprecating v. 1 <-> v. 2 switch.

Summarizing, I would think about cementing the present stuff (which is maintenance anyway) only if there is no other way. And only with proclaimed EoL date.

@jkartseva
Copy link
Author

@mrc0mmand

Thank you! I mentioned that in the kernel mailing list.
As for Arch Linux, what's the procedure of maintenance? Once it's there at least libbpf version needs to be bumped along with the one in GH mirror. Would you like to do that? :) [1] to track libbpf updates.

Alternatively, I can do that. Could you please provide a brief instruction due to I haven't published anything to AUR yet.

And thanks again.
[1] https://help.github.com/en/articles/watching-and-unwatching-releases-for-a-repository

@jkartseva
Copy link
Author

@boucman

This is usually a strong sign that those libraries do not support cross-compilation which is essential for the embedded world. So... this would probably block any systemd upgrade in the embedded world, which is bad. especially if it's a mandatory dependency.

Could you please file a bug report to [1] if you see any issues with cross compilation?

We can also think about a test for that, if given proper repro steps. Is there a test which checks x-compilation for systemd?

[1] https://github.com/libbpf/libbpf/issues

@mrc0mmand
Copy link
Member

@mrc0mmand

Thank you! I mentioned that in the kernel mailing list.
As for Arch Linux, what's the procedure of maintenance? Once it's there at least libbpf version needs to be bumped along with the one in GH mirror. Would you like to do that? :) [1] to track libbpf updates.

Alternatively, I can do that. Could you please provide a brief instruction due to I haven't published anything to AUR yet.

And thanks again.
[1] https://help.github.com/en/articles/watching-and-unwatching-releases-for-a-repository

I'll look into that, as I'll have to monitor the libbpf version anyway for the COPR repo (at least until its present in the EPEL) :-)

@mrc0mmand
Copy link
Member

@wat-ze-hex hmm, I noticed that libbpf seems to already part of this AUR package: https://aur.archlinux.org/packages/bcc-tools/, so I guess we could use that.

@mrc0mmand
Copy link
Member

mrc0mmand commented Oct 14, 2019

Anyway, frankly, using AUR is not that much different than just cloning the libbpf repo and compiling it (as AUR packages have to be compiled locally anyway). Thus, I'm inclining to just add the git clone && make && make install combo to the bootstrap phase and be done with it, as it sound much easier than dealing with the AUR machinery.

@jkartseva
Copy link
Author

@wat-ze-hex hmm, I noticed that libbpf seems to already part of this AUR package: https://aur.archlinux.org/packages/bcc-tools/, so I guess we could use that.

This looks fine with the exception that we don't need bcc portion of it. libbpf comes as a submodule of bcc and the version is bumped with a commit.
There is a discussion to make libbpf a package dependency, so things may change.

So yeah, let's use use bcc in Arch tests.

@jkartseva jkartseva force-pushed the use-libbpf branch 2 times, most recently from 163fbed to 480ef09 Compare December 3, 2019 22:53
@jkartseva
Copy link
Author

Seems that the present bionic failures in systemd-nspawn are due to the devices previously whitelisted by BPF, e.g. /dev/tty are not whitelisted anymore:

Failed to allocate a pty: Operation not permitted

That needs a fix.

@ddstreet
Copy link
Contributor

ddstreet commented Dec 5, 2019

@ddstreet given that it's not the first we've had trouble figuring out what exactly goes wrong when the package is installed there I'm wondering if it would be possible to save the journal somewhere?

the journal is saved for some tests, in the 'artifacts' tarball; but for test-exec (run by the 'root-unittests' autopkgtest) the journal doesn't get saved. I'll open a Debian MR to update the test to save the journal on failure, but even then it will still be in the 'artifacts' tarball. You can get that tarball by using the same URL for the log.gz file, but replace 'log.gz' at the end with 'artifacts.tar.gz'. The Ubuntu CI server could use improvement since that's not obvious at all.

Judging by the number of jobs in the queues on Ubuntu CI (where currently the jobs submitted at 09:29:38 on 2019-12-02 are being run) it got stuck completely. @ddstreet I'm wondering if it's a glitch of some kind.

I'm not exactly sure, but there were infrastructure problems earlier this week that might be the cause.

You can check this page: https://status.admin.canonical.com/
It doesn't specifically list status of the Ubuntu CI lab, but when it shows lots of stuff down (like on Dec 2) that probably means the Ubuntu CI test systems will have problems, too.

@jkartseva
Copy link
Author

@ddstreet

Any advice on how to repro autopkgtest failure?

Keeping running into this:

hostnamed            PASS
localed-locale       PASS
localed-x11-keymap   PASS
logind               PASS
unit-config          PASS
storage              PASS
networkd-test.py     PASS
build-login          PASS
boot-and-services    FAIL non-zero exit status 1
udev                 PASS
root-unittests       PASS
upstream             FAIL non-zero exit status 1
boot-smoke           PASS

Failing w/ e.g. Failed to allocate a pty: Operation not permitted.
That is probably has something to do with the changes I've made. Thanks!

@martinpitt
Copy link
Contributor

See https://www.freedesktop.org/wiki/Software/systemd/autopkgtest/ for how to locally reproduce and investigate the test failures.

@jkartseva
Copy link
Author

@keszybz @evverx
Ok, figured it out. It's green. Review, please?

@jkartseva
Copy link
Author

jkartseva commented Dec 19, 2019

@poettering @keszybz

Ping :) This PR needs some <3.

  1. FYI, we've been working on porting kernel's selftests/ to libbpf. That's partially done by extending Travis CI tests so it can run commands of our choice against different kernels libbpf: Add VMTEST to CI libbpf/libbpf#108. So we're ready to port the tests.
    As was promised at ASG we won't break you... much :)

  2. What's your high level vision for this PR?
    Mine is: It won't get merged until libbpf published to more distros, as we agreed in bpf: introduce libbpf dependency; replace some bpf syscall with libbpf API #13744 (comment), and that's OK.
    Until that happy moment when we proclaim that systemd is ready to have libbpf dependency, I can iterate on this PR by adding more commits on top w/o merging. An iterative feedback and code reviews would be very helpful, so we are on the same page and no surprises at the end.

  3. There is another pending BPF PR which extends current usability by introducing other cgroup attach types. It doesn't require libbpf. I suggest to merge it independently from this PR.

Thoughts? Thanks!

@mrc0mmand
Copy link
Member

@wat-ze-hex how safe is to drop the newly-introduced kernel-headers >= 5.4.0-0.rc6.git0.1[0] dep in the Fedora libbpf (libbpf-devel) package? I was about to bump the libbpf package in our CentOS 7 systemd repo[1], but this dependency would render it uninstallable.

[0] https://src.fedoraproject.org/rpms/libbpf/blob/master/f/libbpf.spec#_28
[1] https://copr.fedorainfracloud.org/coprs/mrc0mmand/systemd-centos-ci/package/libbpf/

@jkartseva
Copy link
Author

@mrc0mmand

Having kernel-headers dependency is essential because otherwise libbpf lib would be built with the headers presently installed on the platform and they can be outdated. This can cause e.g. having an outdated set of program|map|attach types.
See:

$ cd $HOME/libbpf
$ find . -name *.[ch] | xargs grep "<linux/bpf.h>"
./src/bpf.c:#include <linux/bpf.h>
./src/bpf.h:#include <linux/bpf.h>
./src/bpf_prog_linfo.c:#include <linux/bpf.h>
./src/libbpf.c:#include <linux/bpf.h>
./src/libbpf.h:#include <linux/bpf.h>
./src/netlink.c:#include <linux/bpf.h>
./include/linux/filter.h:#include <linux/bpf.h>

Bumping to 0.0.6 is a bit early, the present release version for Rawhide is 0.0.5, see [1]. 0.0.6 build exists as a release candidate.

[1] https://apps.fedoraproject.org/packages/libbpf/overview/

@mrc0mmand
Copy link
Member

@mrc0mmand

Having kernel-headers dependency is essential because otherwise libbpf lib would be built with the headers presently installed on the platform and they can be outdated. This can cause e.g. having an outdated set of program|map|attach types.

I see. I completely understand the need of having a dependency on kernel-headers, I'm more curious about the version of it, i.e. if 5.4.0-0.rc6.git0.1 headers have some features which are required by newer libbpf, thus making it unusable on CentOS 7 (which has 3.10.0-1062.9.1).

Bumping to 0.0.6 is a bit early, the present release version for Rawhide is 0.0.5, see [1]. 0.0.6 build exists as a release candidate.

Ah, I see, will wait a bit then!

[1] https://apps.fedoraproject.org/packages/libbpf/overview/

Copy link
Member

@poettering poettering left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, what does libbpf bring to the table for this btw? it's just a thin, trivial wrapper around the syscall, no? i.e. if it's that simple is the extra dependency really worth it? is there anything non-trivial it provides us with?

If i understand correctly its not even a shared lib yet, i.e. unstable API?

Compare with the keyring APIs. Yes there's a keyring library, but we don't link to it, since all we really need from it are trivial syscall wrappers which is are like 5 lines each. For that kind of stuff its not really worth linking to libbpf, is it?

Can you elaborate?

(I am not strictly against adding new deps, but each new dep must have a strong motivation, i.e. do something substantially more complex thatn just syscall wrapping of a single syscall...)


int bpf_devices_cgroup_init(BPFProgram **ret, CGroupDevicePolicy policy, bool whitelist) {
log_error("BPF is not supported. Mock is called");
return -1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we exclusively return negative errno-style errors here. i.e. usw return -EOPNOTSUPP ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or actually:

return log_error_errno(EOPNOTSUPP, "BPF …");

const char *cgroup_path,
BPFProgram **prog_installed) {
log_error("BPF is not supported. Mock is called");
return -1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto (and everywhere else)

static void unit_prune_cgroup_bpf(Unit *u) {
#if HAVE_LIBBPF
u->bpf_device_control_installed = bpf_program_unref(u->bpf_device_control_installed);
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

such ifdeffery should be left to the implementation of bpf_program_unref(), not the users

int bpf_devices_whitelist_static(BPFProgram *prog, const char *path) {
log_error("BPF is not supported. Mock is called");
return -1;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we usually keep such "not implemented" stubs as inline functions in the headers, so that they are optimized away...

assert(paths);

#if !(HAVE_LIBBPF)
log_syntax(unit, LOG_ERR, filename, line, -1, "libbpf is not found, ignoring %m");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do not make up error codes... i.e. no -1 please. use 0 here...
also why have this ifdeffery at all here? when bpf is disabled we should still compile the parsers for this, and this function at its end already covers the non-bpf case...

memcpy(key_ipv4->data, &a->address, sizeof(uint32_t));

r = bpf_map_update_element(ipv4_map_fd, key_ipv4, &value);
r = bpf_map_update_elem(ipv4_map_fd, key_ipv4, &value, BPF_ANY);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does libbpf do error handling? we use negative return -errno style returns, and what does libbpf do? if they return -1 and set errno, this needs more love

@poettering poettering added needs-discussion 🤔 reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks labels Jan 3, 2020
@jkartseva
Copy link
Author

@poettering

Thanks for reviewing!

Hmm, what does libbpf bring to the table for this btw? it's just a thin, trivial wrapper around the syscall, no? i.e. if it's that simple is the extra dependency really worth it? is there anything non-trivial it provides us with?

In this PR it's a syscall replacement: I'm not comfortable with introducing more changes in a single pull request, prefer smaller atomic changes. Though I can continue adding commits with functional changes in this PR, namely replacing macro assembly with C code. That's merely a matter of code organization. If only there were a way to stack PRs, so major features like this are not merged at once.
So that's up to you, I can continue growing this PR plus addressing the comments you've posted, re-requesting code reviews as more functional changes are added.

If i understand correctly its not even a shared lib yet, i.e. unstable API?

It's a shared lib. There is Fedora package also @mrc0mmand created a package for CentOS and libbpf is linked dynamically given a package.

@poettering
Copy link
Member

Hmm, so I think I'd prefer sticking with our syscall wrappers for now, i.e. use libbpf only if it brings more to the table for us than just syscall wrappers. I hope that makes sense?

@jkartseva
Copy link
Author

@poettering

Sure, I'll extend this PR beyond syscall wrappers, namely replace raw bpf instructions with programs in C. Will request re-review once it's ready.

Julia Kartseva added 2 commits January 20, 2020 18:31
libbpf-dev is a Debian libbpf package built from kernel sources.
That is suboptimal due to Debian libbpf updates are not tied
to libbpf release process including tagging and testing.
Nevertheless it's used to unblock Debian related testing in TravisCI
until a proper packege built from github mirror [1] is out.

[1] https://github.com/libbpf/libbpf
bpf-firewall.h is not used in src/core/dbus-unit.c and
src/core/ip-address-access.c so remove it.
wat-ze-hex added 2 commits January 20, 2020 20:11
Introduce HAVE_LIBBPF macro checking the presence of libbpf package
in the system;
Introduce mock implementation of BPF interface in
bpf-{firewall|devices|program}-mock.c, use mock implementation if
libbpf is not found;
Mock implementation of bpf_{firewall|devices}_supported returns 0,
so other BPF dependent doesn't get executed.
In order to rewrite src/core/bpf-devices.{c|h},
src/core/bpf-devices/bpf-firewall.{c|h} from macro-assembly to eBPF, libbpf
library must be linked to libcore.a.
Replace
  int bpf_map_new(enum bpf_map_type type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags);
  int bpf_map_update_element(int fd, const void *key, void *value);
  int bpf_map_lookup_element(int fd, const void *key, void *value);
with functions from libbpf.
Replace BPF_PROG_LOAD, BPF_PROG_LOAD, BPF_OBJ_GET syscalls.
@mrc0mmand
Copy link
Member

mrc0mmand commented Jan 21, 2020

Something's off:

    archlinux_systemd_ci: FAILED: src/shared/libsystemd-shared-244.so 
    archlinux_systemd_ci: cc  -o src/shared/libsystemd-shared-244.so 'src/shared/5afaae1@@systemd-shared-244@sha/.._libudev_libudev.c.o' 'src/shared/5afaae1@@systemd-shared-244@sha/.._libudev_libudev-device.c.o' 'src/shared/5afaae1@@systemd-shared-244@sha/.._libudev_libudev-enumerate.c.o' 'src/shared/5afaae1@@systemd-shared-244@sha/.._libudev_libudev-hwdb.c.o' 'src/shared/5afaae1@@systemd-shared-244@sha/.._libudev_libudev-list.c.o' 'src/shared/5afaae1@@systemd-shared-244@sha/.._libudev_libudev-monitor.c.o' 'src/shared/5afaae1@@systemd-shared-244@sha/.._libudev_libudev-queue.c.o' 'src/shared/5afaae1@@systemd-shared-244@sha/.._libudev_libudev-util.c.o' -fsanitize=address,undefined -Wl,--as-needed -Wl,--no-undefined -shared -fPIC -Wl,--start-group -Wl,-soname,libsystemd-shared-244.so -Wl,--whole-archive src/shared/libsystemd-shared-244.a src/basic/libbasic.a src/basic/libbasic-gcrypt.a src/libsystemd/libsystemd_static.a src/journal/libjournal-client.a -Wl,--no-whole-archive -Wl,-z,relro -Wl,-z,now -fstack-protector -Wl,--gc-sections -shared -fPIC -Wl,--version-script=/build/src/shared/libshared.sym -pthread -lacl /usr/lib/libblkid.so /usr/lib64/libbpf.a /usr/lib64/libelf.a /usr/lib64/libz.a /lib64/libcap.so -lcrypt /usr/lib/libcryptsetup.so -lgcrypt /usr/lib/libidn2.so /usr/lib/libip4tc.so /usr/lib/libip6tc.so /usr/lib/libkmod.so /usr/lib/liblz4.so /usr/lib/libmount.so /usr/lib/libssl.so /usr/lib/libcrypto.so /usr/lib/libp11-kit.so -lpam -lrt /usr/lib/libseccomp.so /usr/lib/liblzma.so -lacl -lcrypt -lgcrypt -lpam -lm -lgcrypt -Wl,--end-group -Wl,-rpath,/lib64 -Wl,-rpath-link,/lib64
    archlinux_systemd_ci: /usr/bin/ld: /usr/lib64/libelf.a(elf_error.o): relocation R_X86_64_TPOFF32 against `global_error' can not be used when making a shared object; recompile with -fPIC
    archlinux_systemd_ci: /usr/bin/ld: /usr/lib64/libbpf.a(libbpf.o): relocation R_X86_64_PC32 against symbol `stderr@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
    archlinux_systemd_ci: /usr/bin/ld: final link failed: bad value
    archlinux_systemd_ci: collect2: error: ld returned 1 exit status

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bpf needs-discussion 🤔 reviewed/needs-rework 🔨 PR has been reviewed and needs another round of reworks

Development

Successfully merging this pull request may close these issues.