New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for BPF_PROG_TYPE_EXT #127
Conversation
e8c4475
to
d8f9a56
Compare
Here's a proposed API for
let pass: &mut Extension = bpf2.program_mut("pass").unwrap().try_into()?;
pass.load(link_fd, "prog0".to_string())?;
pass.attach(link_fd)?; It's still not working as yet, as I've got to add This is the full example: use aya::programs::{Xdp, XdpFlags, Extension, LinkRef};
use aya::{include_bytes_aligned, Bpf, BpfLoader};
use std::{
convert::{TryInto},
sync::atomic::{AtomicBool, Ordering},
sync::Arc,
thread,
time::Duration,
};
use structopt::StructOpt;
fn main() {
env_logger::init();
if let Err(e) = try_main() {
eprintln!("error: {:#}", e);
}
}
#[derive(Debug, StructOpt)]
struct Opt {
#[structopt(short, long, default_value = "eth0")]
iface: String,
}
fn try_main() -> Result<(), anyhow::Error> {
let opt = Opt::from_args();
let mut bpf = Bpf::load(include_bytes_aligned!("../../xdp_dispatcher.bpf.o"))?;
let program: &mut Xdp = bpf.program_mut("dispatcher").unwrap().try_into()?;
program.load()?;
let path = "/sys/fs/bpf/xdp_dispatcher";
program.attach(&opt.iface, XdpFlags::default())?;
bpf.program_mut("dispatcher").unwrap().pin(path)?;
let prog_ref = LinkRef::from_pinned_path(path)?;
let link_fd = prog_ref.fd().unwrap();
let mut bpf2 = BpfLoader::new().prog_freplace().load(include_bytes_aligned!("../../xdp_pass.bpf.o"))?;
let pass: &mut Extension = bpf2.program_mut("pass").unwrap().try_into()?;
pass.load(link_fd, "prog0".to_string())?;
pass.attach(link_fd)?;
let running = Arc::new(AtomicBool::new(true));
let r = running.clone();
ctrlc::set_handler(move || {
r.store(false, Ordering::SeqCst);
})
.expect("Error setting Ctrl-C handler");
println!("Waiting for Ctrl-C...");
while running.load(Ordering::SeqCst) {
thread::sleep(Duration::from_millis(500))
}
println!("Exiting...");
Ok(())
} |
82b348f
to
2ccec95
Compare
Updated PR with a better description since this is 90% done now. Will push one more commit to do more fixups before loading to the kernel. We'll have to probe for kernel support since I guess it's possible that some distro vendors might backport some of these features at somepoint. |
d5c4f52
to
133179f
Compare
bb7510a
to
670568f
Compare
|
Rebased! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is incredible, you're a hero
// Start DataSec Fixups | ||
let sec_name = self.type_name(t)?.ok_or(BtfError::InvalidTypeInfo)?; | ||
let name = sec_name.to_string(); | ||
// There are cases when the compiler does indeed populate the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a test case that repros when LLVM sets the size vs when it doesn't? I'm happy to fix this in LLVM if it's a bug
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's expected behaviour. See https://reviews.llvm.org/D59441
At the time of debug info emission, the data section
size is unknown, so the btf_type.size = 0 for
BTF_KIND_DATASEC.
I don't remember if I saw a comment in libbpf or LLVM that triggered me to add this conditional
@alessandrod comments addressed, docs improved and here's a working example https://github.com/dave-tucker/aya-ext-test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the doc comments (including #127 (comment) which vscode put in the old review omg) and the AsRef stuff
e1cea0d
to
5317f1a
Compare
@alessandrod addressed docs comments and removed the AsRef stuff. Now you need to use |
This allows for parsed BTF to be re-encoded such that it could be loaded in to the kernel. It moves bytes_of to the utils package. We could use Object::bytes_of, but this requires the impl of the Pod trait on generated code. Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some minor changes, and we're finally done!
This requires loading the BTF to kernel when loading all programs as well as implementing Extension program type Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
Thank you so much this PR is 🔥 |
This PR add support for
BPF_PROG_TYPE_EXT
These program types can be used to replace a function (freplace) of an already loaded BPF program.
In order to to this we must ensure that when the main program is loaded, its BTF is also loaded into the kernel.
This requires that we also provide
func_info
andline_info
In order to load BTF to the kernel safely, this PR also implements feature probing.
This allows us to detect BTF feature support and conditionally enable/disable parts of the loading process and/or fix the BTF provided by LLVM to work with the current running kernel.
func_info
andline_info
from the.BTF.ext
ELF section, including in cases where we link functions from other ELF sections.BTF
and.BTF.ext
and section, we will load these in to the kernelBPF_PROG_LOAD
syscall for ease of finding programs laterAs a result, when loading a BPF program (written in C, with BTF) we get line information included in the output from
bpftool prog dump xlated
, as well as the ability to inspect a loaded programs BTF withbpftool btf dump
.The API for
BPF_PROG_TYPE_EXT
. The API is as follows:let ext : &mut Extension = bpf.programs_mut("xdp_pass").unwrap().try_into()
Extension
program, we need the BPF FD of the program we are targeting. This can be obtained from aLinkRef
if we have one in scope, usingLinkRef::fd()
. Since it's likely that the root program may be pinned, I also implementedLinkRef::from_pinned_path()
.The API for load and attach is as follows: