- Add helper methods to get useful information from the ProgramInfo
object which is returned by the `loaded_programs()` API. Specifically
this code mirrors the `bpftool prog` command in terms of useful fields.
- Add a new API macro to each aya `Program` type to allow us to fetch
its accompanying `ProgramInfo` metadata after its been loaded.
- Add a new ProgramInfo constructor that builds a new instance using
a raw fd.
- Add a smoke test for the loaded_programs() API as well as
all the relevant methods on the ProgramInfo type.
Signed-off-by: Andrew Stoycos <astoycos@redhat.com>
Some of these functions fail to compile when not inlined, so we should
be explicit.
Before deciding on this approach I tried various ways of making all
these functions #[inline(never)] to save instructions but I ran into
blockers:
- These functions currently return Result, which is a structure. This is
not permitted in BPF.
- I tried inventing a newtype that is a #[repr(transparent)] wrapper of
u16, and having these functions return that; however it seems that
even if the object code is legal, the verifier will reject such
functions because the BTF (if present, and it was in my local
experiments) would indicate that the return is a structure.
- I tried having these functions return a plain u16 where 0 means error,
but the verifier still rejected the BTF because the receiver (even if
made into &self) is considered a structure, and forbidden.
We can eventually overcome these problems by "lying" in our BTF once
support for it matures in the bpf-linker repo (e.g. Option<NonZeroU16>
should be perfectly legal as it is guaranteed to be word-sized), but we
aren't there yet, and this is the safest thing we can do for now.
The struct_flavors test previously expected the same thing with and
without relocations. It now expects different values.
Also rename an enum variant "u64" to "S64". This was a typo. Turns out
that U32 is a type that exists in kernel headers, so all enum values are
suffixed with "_VAL".
Remove stdlib.h and the call to exit(). This alone makes the test fail
with a poisoned relocation. Bringing over the map definition makes the
test work again.
For unclear reasons, two of the integration tests related to uprobes
were resolving a symbol in libc. The integration-test binary can be
built statically, in which case it would not load or reference libc.
Statically linking the integration tests and running them in a VM
without a userland is a convenient mechanism to exercise the tests
against different kernel versions.
The fact that the statically linked integration-test binary does not
load libc is not the only reason these tests failed in such an
environment. In fact, the logic to look in the process's memory
maps was not running (because no pid was being passed).
Separate logic to determine which object file to use when attempting
to resolve a symbol for attaching a uprobe changes its behavior based
on whether that target is an absolute path. If the target is not an
absolute path, the code searches through the LdSoCache. This cache does
not always exist in linux systems; when an attach call is made with a
relative path target and there is no /etc/ld.so.cache file, the attach
call will fail. This commit does not change that behavior, it merely
sidesteps it.
Move the use of clang and llvm-objcopy from run-time to build-time. This
allows the integration tests to run on VMs with simpler userlands.
Create a new CI job to build the integration tests separately from
running them. Ship them from that job to the runner job using github
actions artifacts.
The aya-bpf-macros needed refactoring for:
1. Ease of testing
2. To be consistent with when we use K/V args vs. idents
3. To deprecate the use of `name` to change the exported name of a
function - we now use the symbol table.
Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
This makes a few changes to the way that Aya reads the ELF object
files.
1. To find programs in a section, we use the symbols table. This allows
for cases where multiple programs could appear in the same section.
2. When parsing our ELF file we build symbols_by_section_index as an
optimization as we use it for legacy maps, BTF maps and now programs.
As a result of theses changes the "NAME" used in `bpf.prog_mut("NAME")`
is now ALWAYS the same as the function name in the eBPF code, making the
user experience more consistent.
Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
For tests that do networking operations, this allows to have a
clean-state network namespace and interfaces for each test. Mainly, this
avoids "device or resource busy" errors when reusing the loopback
interface across tests.
In release, the trigger functions were being optimized out and the
tests did not work. Use core::hint::black_box to ensure that the
functions are not optimized out. Also, run these integration tests
in CI to ensure that we don't regress.
The matches crate has been archived now that `matches!` is in std.
However `assert_matches!` is still unstable in std, and the
assert_matches crate provides a more expressive form:
```
assert_matches!(foo, Ok(bar) => {
assert_eq!(bar, baz);
});
```
in the integration tests we recenctly switched to using
our internal api to list programs. I was seeing times when
this would race and panic internally (program fd was deleted
by aya WHILE we were trying to get it). This ensures that
the list succeeded without panicking.
Signed-off-by: Andrew Stoycos <astoycos@redhat.com>
Add integration testing for link pinning and
loading/unloading of tracepoint, kprobe, and
uprobe programs.
Redo how we utilize bpftool to verify that programs
are loaded to be explicit with names. Also add a helper
to verify that a program is loaded AND linked.
Signed-off-by: Andrew Stoycos <astoycos@redhat.com>
"integration tests" as defined by Cargo produce a binary per file in the
tests directory. This is really not what we want and has a number of
downsides, but the main one is binary size.
Before:
tamird@pc:~/src/aya$ cargo xtask build-integration-test | xargs ls -lah
Finished dev [unoptimized + debuginfo] target(s) in 0.05s
Running `target/debug/xtask build-integration-test`
Compiling integration-test v0.1.0 (/home/tamird/src/aya/test/integration-test)
Finished dev [unoptimized + debuginfo] target(s) in 0.68s
-rwxrwxr-x 1 tamird tamird 34M Jul 12 15:21 /home/tamird/src/aya/target/debug/deps/bpf_probe_read-e03eb905a5e6209c
-rwxrwxr-x 1 tamird tamird 35M Jul 12 15:21 /home/tamird/src/aya/target/debug/deps/btf_relocations-57a4fbb38bf06064
-rwxrwxr-x 1 tamird tamird 31M Jul 12 15:21 /home/tamird/src/aya/target/debug/deps/elf-98b7a32d6d04effb
-rwxrwxr-x 1 tamird tamird 6.9M Jul 12 15:21 /home/tamird/src/aya/target/debug/deps/integration_test-0dd55ce96bfdad77
-rwxrwxr-x 1 tamird tamird 34M Jul 12 15:21 /home/tamird/src/aya/target/debug/deps/load-0718562e85b86d03
-rwxrwxr-x 1 tamird tamird 40M Jul 12 15:21 /home/tamird/src/aya/target/debug/deps/log-dbf355f9ea34068a
-rwxrwxr-x 1 tamird tamird 36M Jul 12 15:21 /home/tamird/src/aya/target/debug/deps/rbpf-89a1bb848fa5cc3c
-rwxrwxr-x 1 tamird tamird 34M Jul 12 15:21 /home/tamird/src/aya/target/debug/deps/relocations-cfe655c3bb413d8b
-rwxrwxr-x 1 tamird tamird 34M Jul 12 15:21 /home/tamird/src/aya/target/debug/deps/smoke-ccd3974180a3fd29
After:
tamird@pc:~/src/aya$ cargo xtask build-integration-test | xargs ls -lah
Finished dev [unoptimized + debuginfo] target(s) in 0.05s
Running `target/debug/xtask build-integration-test`
Compiling integration-test v0.1.0 (/home/tamird/src/aya/test/integration-test)
Finished dev [unoptimized + debuginfo] target(s) in 0.90s
-rwxrwxr-x 1 tamird tamird 47M Jul 12 15:21 /home/tamird/src/aya/target/debug/deps/integration_test-0dd55ce96bfdad77
Since we plan to run these tests in a VM, copying 10x fewer bytes seems
like a win.
- Add libbpf as a submodule. This prevents having to plumb its location
around (which can't be passed to Cargo build scripts) and also
controls the version against which codegen has run.
- Move bpf written in C to the integration-test crate and define
constants for each probe.
- Remove magic; each C source file must be directly enumerated in the
build script and in lib.rs.
This doesn't add any value; use `cargo build --tests` with
`--message-format=json` instead; parse the output using `cargo_metadata`
to discover the location of the test binary.
Move test/integration-test/src/tests -> test/integration-test/tests to
conform to
https://doc.rust-lang.org/book/ch11-03-test-organization.html#integration-tests.
This change does a few things:
- it fixes a bug in the wrappers, where we were expecting the kernel to
return len=1 for b"\0" where it instead returns 0 and doesn't write
out the NULL terminator
- it makes the helpers more robust by hardcoding bound checks in
assembly so that LLVM optimizations can't transform the checks in a
way that the verifier can't understand.
- it adds integration tests
This fix aya wrong logic causing non entrypoint functions to not have
any BTF relocations working.
Also fix missing section_offset computation for instruction offset in
multiple spots.
This commit adds from_pin() which allows the creation of a Program
from a path on bpffs. This is useful to be able to call `attach` or
other APIs for programs that are already loaded to the kernel.
This differs from #444 since it implements this on the concrete program
type, not the Program enum, allowing the user to pass in any additional
context that isn't available from bpf_prog_info.
Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
Before this chane, the check was always negative if the minor version
was less then 9. So, for example, the smoke test was skipped for kernel
6.1:
```
skipping as 6.1 does not meet version requirement of 5.9
```
Signed-off-by: Michal Rostecki <vadorovsky@gmail.com>
Simplifiy the relocation tests build process by removing the need for libbpf
at runtime. Its usage is replaced with local `__builtin_*` attributes.
This removes the need for the `LIBBPF_INCLUDE` env variable.
This commit adds documentation on how program names are parsed from
section names, as is used by `aya_obj::Object.programs` as HashMap keys,
and updates the examples into using program names.
Instead of returning anyhow>>Result<()> handle errors
'in-place' with unwrap or panic, for more informative
and user-friendly error messages on test failures.
Fixes#421.
Signed-off-by: Dmitry Savintsev <dsavints@gmail.com>
switch map() and map_mut() from returning a
`Result` to an `Option` since it's just getting
a value from a Hashmap, and to stay in line with
the Programs API.
Remove `MapError::MapNotFound`
Signed-off-by: Andrew Stoycos <astoycos@redhat.com>
Build completing tests passing
Refactor the Map API to better align
with the aya programs API. Specifically
remove all internal locking mechanisms
and custom Deref/DerefMut implementations.
They are replaced with a Map enum
and AsRef/AsMut implementations.
All Try_From implementations have been moved
to standardized enums, with a slightly
special one for PerfEventArray's.
Also cleanup/fix all associated tests and
documentation.
Signed-off-by: Andrew Stoycos <astoycos@redhat.com>
We often need to wait a bit until the program or link gets unloaded
after dropping.
Also, using a macro makes it clear in which particular test the panic
happened.
Signed-off-by: Michal Rostecki <vadorovsky@gmail.com>
libbpf 1.0 doesn't support multimaps defined in `maps` section, it
supports only BTF maps.
At the same time, we already test multimaps loading with the Rust
example (`integration-ebpf/src/bpf/map_test.rs`), so we can just remove
the failing C test.
Signed-off-by: Michal Rostecki <vadorovsky@gmail.com>
1. Removes OwnedLink
2. Allows Links to be converted into FdLink
3. Introduces a PinnedLink type to handle wrap FdLink when pinned and
support un-pinning
Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
This commit allows for BTF maps in the .maps ELF section to be parsed.
It reads the necessary information from the BTF section of the ELF file.
While the btf_ids of Keys and Values types are stored, they are not (yet)
used.
When creating a BTF map, we pass the btf_key_type_id and
btf_value_type_id.
Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
This commit replaces the existing RTF test runner with a simple rust
binary package called - integration-test.
integration-test depends on integration-ebpf, which contains test eBPF
code written in Rust and C. `cargo xtask build-integration-test-ebpf`
can be used to build this code and supress rust-analyzer warnings. It
does require `bpf-linker`, but that is highly likely to be available to
developers of Aya. It also requires a checkout of `libbpf` to extract
headers like bpf-helpers.h.
Since everything is compiled into a single binary, it can be run
be run locally using `cargo xtask integration-test` or remotely using
`./run.sh` which re-uses the bash script from the old test framework
to spawn a VM in which to run the tests.
Signed-off-by: Dave Tucker <dave@dtucker.co.uk>