Skip to content

Commit

Permalink
Add GitHub CI and fix test runner bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
parttimenerd committed Jan 29, 2024
1 parent 606924e commit 91d843b
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 31 deletions.
66 changes: 66 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -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-23.10
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-23.10
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 llvm clang

- 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'
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Hello eBPF
==========

[![ci](https://github.com/parttimenerd/hello-ebpf/actions/workflows/ci.yml/badge.svg)](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.
Expand Down
2 changes: 1 addition & 1 deletion bcc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
<dependency>
<groupId>me.bechberger</groupId>
<artifactId>rawbcc</artifactId>
<version>0.1.1</version>
<version>0.1.2</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
Expand Down
12 changes: 11 additions & 1 deletion bcc/src/main/java/me/bechberger/ebpf/bcc/BPF.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import me.bechberger.ebpf.bcc.raw.Lib;
import org.jetbrains.annotations.Nullable;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemorySegment;
Expand All @@ -25,6 +27,11 @@
public class BPF implements AutoCloseable {

static {
if (!LibraryLoader.isInstalled()) {
throw new RuntimeException("BCC library is not installed");
} else {
System.err.println("BCC library is installed");
}
LibraryLoader.load();
}

Expand Down Expand Up @@ -142,10 +149,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}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
8 changes: 8 additions & 0 deletions rawbcc/CHANGELOG
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion rawbcc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ These bindings are regurlarly updated and published on Maven Central:
<dependency>
<groupId>me.bechberger</groupId>
<artifactId>rawbcc</artifactId>
<version>0.1.1</version>
<version>0.1.2</version>
</dependency>
```

Expand Down
2 changes: 1 addition & 1 deletion rawbcc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<groupId>me.bechberger</groupId>
<name>Raw bindings for libbcc</name>

<version>0.1.1</version>
<version>0.1.2</version>
<url>https://github.com/parttimenerd/hello-ebpf</url>
<licenses>
<license>
Expand Down
52 changes: 32 additions & 20 deletions rawbcc/src/main/java/me/bechberger/ebpf/bcc/raw/LibraryLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path> 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<Path> 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());
}

/**
Expand All @@ -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());
}
}
7 changes: 3 additions & 4 deletions testutil/bin/java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
$testutil_dir/run-in-container.sh $HBT_KERNEL_VERSION $HBT_JAVA_BINARY $@
2 changes: 0 additions & 2 deletions testutil/find_and_get_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
6 changes: 6 additions & 0 deletions testutil/run-in-container.sh
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ fi
# get exact kernel version which is "$input/lib/modules/<version>/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
Expand Down
4 changes: 4 additions & 0 deletions testutil/setup-and-run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 91d843b

Please sign in to comment.