diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..c744194
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,66 @@
+name: ci
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-22.04
+ timeout-minutes: 10
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Java 21
+ uses: actions/setup-java@v4
+ with:
+ java-version: '21'
+ distribution: 'adopt'
+
+ - name: mvn package
+ run: mvn package -DskipTests
+
+ - name: upload bcc/target/bcc.jar
+ uses: actions/upload-artifact@v4
+ with:
+ name: bcc.jar
+ path: bcc/target/bcc.jar
+
+ vm-test:
+ name: Run tests on pre-built kernel
+ runs-on: ubuntu-22.04
+ needs: build
+ timeout-minutes: 10
+ strategy:
+ matrix:
+ version: ["6.6"]
+ env:
+ HBT_KERNEL_VERSION: "${{ matrix.version }}"
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Java
+ uses: actions/setup-java@v4
+ with:
+ java-version: '21'
+ distribution: 'adopt'
+
+ - run: sudo pip3 install https://github.com/amluto/virtme/archive/beb85146cd91de37ae455eccb6ab67c393e6e290.zip
+ - run: sudo apt-get update && sudo apt-get install -y --no-install-recommends qemu-system-x86 bpfcc-tools libbpfcc libbpfcc-dev linux-headers-$(uname -r) linux-cloud-tools-generic
+
+ - name: Test
+ run: |
+ mvn test -Djvm=testutil/bin/java
+
+ - name: Publish Test Report
+ uses: mikepenz/action-junit-report@v4
+ if: always()
+ with:
+ check_name: 'Test Report (Kernel ${{ matrix.KERNEL_VERSION }})'
+ report_paths: '**/build/test-results/test/TEST-*.xml'
\ No newline at end of file
diff --git a/README.md b/README.md
index 2c8b1b5..dfa1c5b 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
Hello eBPF
==========
+[](https://github.com/parttimenerd/hello-ebpf/actions/workflows/ci.yml)
+
There are [user land libraries](https://ebpf.io/what-is-ebpf/#development-toolchains) for [eBPF](https://ebpf.io) that allow you to
write eBPF applications in C++, Rust, Go, Python and even
Lua. But there are none for Java, which is a pity.
@@ -221,6 +223,7 @@ This requires [virtme](https://github.com/ezequielgarcia/virtme) (`apt install v
You can run custom commands in the container using `testutil/run-in-container.sh`.
Read more in the [testutil/README.md](testutil/README.md).
+I'm unable to get it running in the CI, so I'm currently running the tests locally.
Contributing
------------
diff --git a/bcc/pom.xml b/bcc/pom.xml
index ce1cb76..4b49533 100644
--- a/bcc/pom.xml
+++ b/bcc/pom.xml
@@ -120,7 +120,7 @@
me.bechberger
rawbcc
- 0.1.1
+ 0.1.2
org.junit.jupiter
diff --git a/bcc/src/main/java/me/bechberger/ebpf/bcc/BPF.java b/bcc/src/main/java/me/bechberger/ebpf/bcc/BPF.java
index 58f4137..3fbe0c3 100644
--- a/bcc/src/main/java/me/bechberger/ebpf/bcc/BPF.java
+++ b/bcc/src/main/java/me/bechberger/ebpf/bcc/BPF.java
@@ -142,10 +142,13 @@ private BPF(String text, String fileName, @Nullable Path hdrFile, boolean allowR
cflags_array, len(cflags_array),
allow_rlimit, device)
*/
- var maybeModule = bpf_module_create_c_from_string(arena, textNative, debug, MemorySegment.NULL, 0, allowRLimit ? 1 : 0, MemorySegment.NULL);
+ var maybeModule = bpf_module_create_c_from_string(arena, textNative, -1, MemorySegment.NULL, 0, allowRLimit ? 1 : 0, MemorySegment.NULL);
if (maybeModule.err() != 0 && maybeModule.err() != 2) {
throw new BPFCallException(STR."Failed to compile BPF module: \{PanamaUtil.errnoString(maybeModule.err())}");
}
+ if (maybeModule.err() != 0) {
+ System.err.println(STR."Warning BPF constructor: \{fileName} \{maybeModule.err()} \{PanamaUtil.errnoString(maybeModule.err())}");
+ }
module = maybeModule.result();
if (module == null) throw new RuntimeException(STR."Failed to compile BPF module \{fileName}");
diff --git a/bcc/src/test/java/me/bechberger/ebpf/bcc/structs/HelloBufferTest.java b/bcc/src/test/java/me/bechberger/ebpf/bcc/structs/HelloBufferTest.java
index af0086f..ad6c76e 100644
--- a/bcc/src/test/java/me/bechberger/ebpf/bcc/structs/HelloBufferTest.java
+++ b/bcc/src/test/java/me/bechberger/ebpf/bcc/structs/HelloBufferTest.java
@@ -63,7 +63,7 @@ int hello(void *ctx) {
return 0;
}
- """).build()) {
+ """).withDebug(-1).build()) {
var syscall = b.get_syscall_fnname("execve");
b.attach_kprobe(syscall, "hello");
diff --git a/rawbcc/CHANGELOG b/rawbcc/CHANGELOG
index 2867307..db54650 100644
--- a/rawbcc/CHANGELOG
+++ b/rawbcc/CHANGELOG
@@ -1,5 +1,13 @@
# Changelog
+## 0.1.2
+
+### Fixed
+- Fix loading libraries if the library ends with a version number, like `libbcc.so.0`
+
+### Changed
+- Delegate loading of libraries to `System.load` if possible
+
## 0.1.1
### Fixed
diff --git a/rawbcc/README.md b/rawbcc/README.md
index 5de6b0c..dbb6210 100644
--- a/rawbcc/README.md
+++ b/rawbcc/README.md
@@ -12,7 +12,7 @@ These bindings are regurlarly updated and published on Maven Central:
me.bechberger
rawbcc
- 0.1.1
+ 0.1.2
```
diff --git a/rawbcc/pom.xml b/rawbcc/pom.xml
index ce4bc6c..2a61659 100644
--- a/rawbcc/pom.xml
+++ b/rawbcc/pom.xml
@@ -8,7 +8,7 @@
me.bechberger
Raw bindings for libbcc
- 0.1.1
+ 0.1.2
https://github.com/parttimenerd/hello-ebpf
diff --git a/rawbcc/src/main/java/me/bechberger/ebpf/bcc/raw/LibraryLoader.java b/rawbcc/src/main/java/me/bechberger/ebpf/bcc/raw/LibraryLoader.java
index 7c3936a..b05b129 100644
--- a/rawbcc/src/main/java/me/bechberger/ebpf/bcc/raw/LibraryLoader.java
+++ b/rawbcc/src/main/java/me/bechberger/ebpf/bcc/raw/LibraryLoader.java
@@ -5,32 +5,36 @@
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
import java.util.Optional;
+import java.util.stream.Stream;
/**
* Loads the BCC library
*/
public class LibraryLoader {
+
+ private static Optional findLibInFolder(Path folder, int depth) {
+ try (var stream = Files.walk(folder, depth, FileVisitOption.FOLLOW_LINKS)) {
+ return stream.filter(p -> p.getFileName().toString().startsWith("libbcc.so")).findFirst();
+ } catch (IOException e) {
+ return Optional.empty();
+ }
+ }
private static Optional findBCCLibrary() {
var javaLibraryPath = System.getProperty("java.library.path");
if (javaLibraryPath == null) {
return Optional.empty();
}
- var paths = javaLibraryPath.split(":");
- for (var path : paths) {
- var libPath = Path.of(path + "/libbcc.so");
- if (libPath.toFile().exists()) {
- return Optional.of(libPath);
- }
- }
-
- try (var stream = Files.walk(Path.of("/lib"), 2, FileVisitOption.FOLLOW_LINKS)) {
- return stream.filter(p -> p.endsWith("libbcc.so")).findFirst();
- } catch (IOException e) {
- return Optional.empty();
- }
+ return Arrays.stream(javaLibraryPath.split(":"))
+ .map(f -> findLibInFolder(Path.of(f), 1))
+ .filter(Optional::isPresent).map(Optional::get).findFirst()
+ .or(() -> Stream.of("/lib", "/usr/lib", "/lib64", "/usr/lib64")
+ .map(Path::of)
+ .map(p -> findLibInFolder(p, 2))
+ .filter(Optional::isPresent).map(Optional::get).findFirst());
}
/**
@@ -44,13 +48,21 @@ public static boolean isInstalled() {
* Loads the BCC library and {@code System.exit(1)} if it is not available
*/
public static void load() {
- var lib = findBCCLibrary();
- if (lib.isPresent()) {
- System.load(lib.get().toString());
- return;
+ try {
+ System.loadLibrary("bcc");
+ } catch (UnsatisfiedLinkError e) {
+ var lib = findBCCLibrary();
+ if (lib.isPresent()) {
+ System.load(lib.get().toString());
+ return;
+ }
+ System.err.println("Failed to load libbcc.so, pass the location of the lib folder " +
+ "via -Djava.library.path after you installed it");
+ System.exit(1);
}
- System.err.println("Failed to load libbcc.so, pass the location of the lib folder " +
- "via -Djava.library.path after you installed it");
- System.exit(1);
+ }
+
+ public static void main(String[] args) {
+ System.out.println(isInstalled());
}
}
\ No newline at end of file
diff --git a/testutil/bin/java b/testutil/bin/java
index f72eaa6..e1fe4fe 100755
--- a/testutil/bin/java
+++ b/testutil/bin/java
@@ -6,7 +6,7 @@
#
# Configuration per environment variables:
# - `HBT_JAVA_BINARY` - the java binary to use (default: `java`)
-# - `HBT_KERNEL_VERSION` - the kernel version to use (default: `6.7`)
+# - `HBT_KERNEL_VERSION` - the kernel version to use (default: `6.6`)
# see https://ghcr.io/cilium/ci-kernels for available versions
#
# Has to reside in bin/java so it can be passed to the `-Djvm` maven option.
@@ -20,8 +20,7 @@ set -e
HBT_JAVA_BINARY=${HBT_JAVA_BINARY:-java}
# The kernel version to use
-HBT_KERNEL_VERSION=${HBT_KERNEL_VERSION:-6.7}
+HBT_KERNEL_VERSION=${HBT_KERNEL_VERSION:-6.6}
testutil_dir=$(dirname "$0")/..
-$testutil_dir/run-in-container.sh $HBT_KERNEL_VERSION $HBT_JAVA_BINARY $@
-exit 0
\ No newline at end of file
+$testutil_dir/run-in-container.sh $HBT_KERNEL_VERSION $HBT_JAVA_BINARY $@
\ No newline at end of file
diff --git a/testutil/find_and_get_kernel.py b/testutil/find_and_get_kernel.py
index c21af27..9c1f4d8 100755
--- a/testutil/find_and_get_kernel.py
+++ b/testutil/find_and_get_kernel.py
@@ -135,8 +135,6 @@ def copy_headers_into_dest(arch: str, version: str, dest_root: Path):
argparse.add_argument("version", help="Kernel version")
argparse.add_argument("destination", help="Destination folder")
args = argparse.parse_args()
- print(
- f"Downloading headers for {args.version} (arch {get_arch()}) into {args.destination}")
copy_headers_into_dest(get_arch(),
args.version,
Path(args.destination))
diff --git a/testutil/run-in-container.sh b/testutil/run-in-container.sh
index 2d87c08..1be35d6 100755
--- a/testutil/run-in-container.sh
+++ b/testutil/run-in-container.sh
@@ -72,6 +72,12 @@ fi
# get exact kernel version which is "$input/lib/modules//updates"
kernel_version=$(basename "$(find "${input}/lib/modules" -maxdepth 1 -type d)")
+# /lib is a symlink which causes problems
+mkdir "$input"/lib2
+cp -r "$input"/lib/modules "$input"/lib2
+rm -r "$input"/lib
+mv $input/lib2 $input/lib
+
"$script_folder"/find_and_get_kernel.py "${kernel_version}" "$input"
mkdir -p "$input"/root
diff --git a/testutil/setup-and-run.sh b/testutil/setup-and-run.sh
index 8b4dd6b..844d90a 100644
--- a/testutil/setup-and-run.sh
+++ b/testutil/setup-and-run.sh
@@ -13,4 +13,8 @@ if [[ -d "/run/input/lib/modules" ]]; then
find /run/input/lib/modules -type f -name bpf_testmod.ko -exec insmod {} \;
fi
+# used for debugging to check if bcc works at all
+#script_dir="$(dirname "$(realpath "$0")")"
+#timeout 5 python3 $script_dir/../pysamples/bcc/hello_world.py
+
$* && touch /run/output/status
\ No newline at end of file