Skip to content

Commit

Permalink
Add lib module with conditional imports depending on std/no_std.
Browse files Browse the repository at this point in the history
Signed-off-by: SzymonKubica <[email protected]>

Add correct imports for cranelift feature.

Signed-off-by: SzymonKubica <[email protected]>

Add optional loading of dependencies available only when under std.

Signed-off-by: SzymonKubica <[email protected]>
  • Loading branch information
SzymonKubica committed May 30, 2024
1 parent a8447c9 commit 1544093
Show file tree
Hide file tree
Showing 21 changed files with 445 additions and 290 deletions.
29 changes: 16 additions & 13 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,30 @@ include = [

[dependencies]

combine = "4.6"
libc = "0.2"
time = "0.2"
byteorder = "1.2"
byteorder = { version = "1.2", default-features = false }
log = {version = "0.4.21", default-features = false }

# The following dependencies are only used when `std` is enabled.
combine = { version = "4.6", optional = true }
libc = { version = "0.2", optional = true }
time = {version = "0.2", optional = true }

# Optional Dependencies for the CraneLift JIT
cranelift-codegen = { version = "0.99", optional = true }
cranelift-frontend = { version = "0.99", optional = true }
cranelift-jit = { version = "0.99", optional = true }
cranelift-native = { version = "0.99", optional = true }
cranelift-module = { version = "0.99", optional = true }
cranelift-codegen = { version = "0.99", optional = true }
cranelift-frontend = { version = "0.99", optional = true }
cranelift-jit = { version = "0.99", optional = true }
cranelift-native = { version = "0.99", optional = true }
cranelift-module = { version = "0.99", optional = true }

[dev-dependencies]

elf = "0.0.10"
json = "0.11"
hex = "0.4.3"
elf = { version = "0.0.10", default-features = false }
json = { version = "0.11", default-features = false }
hex = { version = "0.4.3" }

[features]
default = ["std"]
std = []
std = ["dep:time", "dep:libc", "dep:combine"]
cranelift = [
"dep:cranelift-codegen",
"dep:cranelift-frontend",
Expand Down
57 changes: 33 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -447,9 +447,12 @@ fn main() {
let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();

// We register a helper function, that can be called by the program, into
// the VM.
vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX,
helpers::bpf_trace_printf).unwrap();
// the VM. The `bpf_trace_printf` is only available when we have access to
// the standard library.
#[cfg(feature = "std")] {
vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX,
helpers::bpf_trace_printf).unwrap();
}

// This kind of VM takes a reference to the packet data, but does not need
// any reference to the metadata buffer: a fixed buffer is handled
Expand All @@ -469,17 +472,21 @@ methods are available.
The first method consists in using the assembler provided by the crate.

```rust
extern crate rbpf;
use rbpf::assembler::assemble;

let prog = assemble("add64 r1, 0x605
mov64 r2, 0x32
mov64 r1, r0
be16 r0
neg64 r2
exit").unwrap();

println!("{:?}", prog);
extern crate rbpf;
// These tests should only be run on std as they depend on the assembler.
#[cfg(feature = "std")] {
use rbpf::assembler::assemble;

let prog = assemble("add64 r1, 0x605
mov64 r2, 0x32
mov64 r1, r0
be16 r0
neg64 r2
exit").unwrap();

println!("{:?}", prog);
}
```

The above snippet will produce:
Expand All @@ -497,19 +504,21 @@ Conversely, a disassembler is also available to dump instruction names from
bytecode in a human-friendly format.

```rust
extern crate rbpf;
use rbpf::disassembler::disassemble;
#[cfg(feature = "std")] {
extern crate rbpf;
use rbpf::disassembler::disassemble;

let prog = &[
0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
];
let prog = &[
0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
];

disassemble(prog);
disassemble(prog);
}
```

This will produce the following output:
Expand Down
59 changes: 31 additions & 28 deletions examples/disassemble.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,40 @@
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
// Copyright 2017 6WIND S.A. <[email protected]>


extern crate rbpf;
use rbpf::disassembler;

// Simply disassemble a program into human-readable instructions.
fn main() {
let prog = &[
0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x79, 0x12, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
0x79, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0xbf, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0x03, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
0x2d, 0x23, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x69, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0x02, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00,
0x71, 0x12, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0x02, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x79, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,
0xbf, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x57, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x15, 0x02, 0x08, 0x00, 0x99, 0x99, 0x00, 0x00,
0x18, 0x02, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x18, 0x02, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1d, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
];
disassembler::disassemble(prog);
#[cfg(feature = "std")] {
let prog = &[
0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x79, 0x12, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
0x79, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0xbf, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0x03, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
0x2d, 0x23, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x69, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0x02, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00,
0x71, 0x12, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0x02, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x79, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,
0xbf, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x57, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x15, 0x02, 0x08, 0x00, 0x99, 0x99, 0x00, 0x00,
0x18, 0x02, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x18, 0x02, 0x00, 0x00, 0x00, 0x00, 0x99, 0x99,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1d, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
];
disassembler::disassemble(prog);
}
}
163 changes: 83 additions & 80 deletions examples/load_elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,85 +49,88 @@ use rbpf::helpers;

fn main() {

let filename = "examples/load_elf__block_a_port.o";

let path = PathBuf::from(filename);
let file = match elf::File::open_path(path) {
Ok(f) => f,
Err(e) => panic!("Error: {:?}", e),
};

let text_scn = match file.get_section(".classifier") {
Some(s) => s,
None => panic!("Failed to look up .classifier section"),
};

let prog = &text_scn.data;

let packet1 = &mut [
0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
0x08, 0x00, // ethertype
0x45, 0x00, 0x00, 0x3b, // start ip_hdr
0xa6, 0xab, 0x40, 0x00,
0x40, 0x06, 0x96, 0x0f,
0x7f, 0x00, 0x00, 0x01,
0x7f, 0x00, 0x00, 0x01,
// Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
0x99, 0x99, 0xc6, 0xcc, // start tcp_hdr
0xd1, 0xe5, 0xc4, 0x9d,
0xd4, 0x30, 0xb5, 0xd2,
0x80, 0x18, 0x01, 0x56,
0xfe, 0x2f, 0x00, 0x00,
0x01, 0x01, 0x08, 0x0a, // start data
0x00, 0x23, 0x75, 0x89,
0x00, 0x23, 0x63, 0x2d,
0x71, 0x64, 0x66, 0x73,
0x64, 0x66, 0x0au8
];

let packet2 = &mut [
0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
0x08, 0x00, // ethertype
0x45, 0x00, 0x00, 0x3b, // start ip_hdr
0xa6, 0xab, 0x40, 0x00,
0x40, 0x06, 0x96, 0x0f,
0x7f, 0x00, 0x00, 0x01,
0x7f, 0x00, 0x00, 0x01,
// Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
0x98, 0x76, 0xc6, 0xcc, // start tcp_hdr
0xd1, 0xe5, 0xc4, 0x9d,
0xd4, 0x30, 0xb5, 0xd2,
0x80, 0x18, 0x01, 0x56,
0xfe, 0x2f, 0x00, 0x00,
0x01, 0x01, 0x08, 0x0a, // start data
0x00, 0x23, 0x75, 0x89,
0x00, 0x23, 0x63, 0x2d,
0x71, 0x64, 0x66, 0x73,
0x64, 0x66, 0x0au8
];

let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf).unwrap();

let res = vm.execute_program(packet1).unwrap();
println!("Packet #1, program returned: {res:?} ({res:#x})");
assert_eq!(res, 0xffffffff);

#[cfg(all(not(windows), feature = "std"))]
{
vm.jit_compile().unwrap();

let res = unsafe { vm.execute_program_jit(packet2).unwrap() };
println!("Packet #2, program returned: {res:?} ({res:#x})");
assert_eq!(res, 0);
}

#[cfg(any(windows, not(feature = "std")))]
{
let res = vm.execute_program(packet2).unwrap();
println!("Packet #2, program returned: {:?} ({:#x})", res, res);
assert_eq!(res, 0);
// This example relies on the bpf_trace_printf which is only available on std
#[cfg(feature = "std")] {
let filename = "examples/load_elf__block_a_port.o";

let path = PathBuf::from(filename);
let file = match elf::File::open_path(path) {
Ok(f) => f,
Err(e) => panic!("Error: {:?}", e),
};

let text_scn = match file.get_section(".classifier") {
Some(s) => s,
None => panic!("Failed to look up .classifier section"),
};

let prog = &text_scn.data;

let packet1 = &mut [
0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
0x08, 0x00, // ethertype
0x45, 0x00, 0x00, 0x3b, // start ip_hdr
0xa6, 0xab, 0x40, 0x00,
0x40, 0x06, 0x96, 0x0f,
0x7f, 0x00, 0x00, 0x01,
0x7f, 0x00, 0x00, 0x01,
// Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
0x99, 0x99, 0xc6, 0xcc, // start tcp_hdr
0xd1, 0xe5, 0xc4, 0x9d,
0xd4, 0x30, 0xb5, 0xd2,
0x80, 0x18, 0x01, 0x56,
0xfe, 0x2f, 0x00, 0x00,
0x01, 0x01, 0x08, 0x0a, // start data
0x00, 0x23, 0x75, 0x89,
0x00, 0x23, 0x63, 0x2d,
0x71, 0x64, 0x66, 0x73,
0x64, 0x66, 0x0au8
];

let packet2 = &mut [
0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
0x08, 0x00, // ethertype
0x45, 0x00, 0x00, 0x3b, // start ip_hdr
0xa6, 0xab, 0x40, 0x00,
0x40, 0x06, 0x96, 0x0f,
0x7f, 0x00, 0x00, 0x01,
0x7f, 0x00, 0x00, 0x01,
// Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
0x98, 0x76, 0xc6, 0xcc, // start tcp_hdr
0xd1, 0xe5, 0xc4, 0x9d,
0xd4, 0x30, 0xb5, 0xd2,
0x80, 0x18, 0x01, 0x56,
0xfe, 0x2f, 0x00, 0x00,
0x01, 0x01, 0x08, 0x0a, // start data
0x00, 0x23, 0x75, 0x89,
0x00, 0x23, 0x63, 0x2d,
0x71, 0x64, 0x66, 0x73,
0x64, 0x66, 0x0au8
];

let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf).unwrap();

let res = vm.execute_program(packet1).unwrap();
println!("Packet #1, program returned: {res:?} ({res:#x})");
assert_eq!(res, 0xffffffff);

#[cfg(not(windows))]
{
vm.jit_compile().unwrap();

let res = unsafe { vm.execute_program_jit(packet2).unwrap() };
println!("Packet #2, program returned: {res:?} ({res:#x})");
assert_eq!(res, 0);
}

#[cfg(windows)]
{
let res = vm.execute_program(packet2).unwrap();
println!("Packet #2, program returned: {:?} ({:#x})", res, res);
assert_eq!(res, 0);
}
}
}
Loading

0 comments on commit 1544093

Please sign in to comment.