Skip to content
Merged

Dev #37

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 82 additions & 7 deletions eclipta-cli/src/commands/ebpf/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,14 @@ pub async fn handle_load(opts: LoadOptions) -> Result<()> {
let should_skip_verifier = requirements.sections.iter()
.all(|s| s.contains("TC"));

if should_skip_verifier {
// Load and attach the program, keeping the Ebpf object alive
let attach_result = if should_skip_verifier {
println!("Skipping Aya verifier for TC-only programs");
attach_program_to_kernel(&program_path, &requirements, &opts).await?
} else {
println!("Loading eBPF program using Aya...");
load_ebpf_with_aya(&program_path)?;
}

println!("Attaching program to kernel...");
let attach_result = attach_program_to_kernel(&program_path, &requirements, &opts).await?;
println!("Loading and attaching eBPF program using Aya...");
load_and_attach_ebpf(&program_path, &requirements, &opts).await?
};

println!("Verifying kernel program attachment...");
verify_kernel_attachment(&requirements, &opts).await?;
Expand Down Expand Up @@ -258,6 +257,81 @@ fn load_ebpf_with_aya(path: &PathBuf) -> Result<()> {
Ok(())
}

async fn load_and_attach_ebpf(
path: &PathBuf,
requirements: &ProgramRequirements,
opts: &LoadOptions
) -> Result<String> {
let mut ebpf = Ebpf::load_file(path)
.context("Failed to load eBPF object with Aya")?;

let map_count = ebpf.maps().count();
if map_count == 0 {
println!("No maps found in eBPF object");
} else {
println!("Found {} maps in eBPF object", map_count);
}

// Load all programs first
for (name, program) in ebpf.programs_mut() {
match load_program_by_type(program) {
Ok(()) => println!("Program '{}' loaded successfully", name),
Err(e) => {
let error_msg = e.to_string();
if error_msg.contains("busy") || error_msg.contains("already") {
println!("Program '{}' already loaded (EBUSY)", name);
continue;
}
return Err(anyhow!("Failed to load program '{}': {}", name, e));
}
}
}

println!("Aya eBPF loading completed successfully");

// Now attach the programs based on type
match requirements.program_type.as_str() {
"XDP" => {
let iface = opts.iface.as_ref()
.ok_or_else(|| anyhow!("Interface required for XDP programs"))?;

for (name, program) in ebpf.programs_mut() {
if let Program::Xdp(xdp_prog) = program {
xdp_prog.attach(iface, aya::programs::XdpFlags::default())
.context("Failed to attach XDP program to interface")?;

println!("XDP program '{}' attached to interface '{}'", name, iface);
return Ok(format!("XDP program attached to {}", iface));
}
}
Err(anyhow!("No XDP program found in eBPF object"))
}

"Tracepoint" => {
let category = requirements.tracepoint_category.as_ref()
.ok_or_else(|| anyhow!("Tracepoint category not found in ELF sections"))?;
let name = requirements.tracepoint_name.as_ref()
.ok_or_else(|| anyhow!("Tracepoint name not found in ELF sections"))?;

for (prog_name, program) in ebpf.programs_mut() {
if let Program::TracePoint(tp_prog) = program {
tp_prog.attach(category, name)
.context(format!("Failed to attach Tracepoint program to '{}:{}'", category, name))?;

println!("Tracepoint program '{}' attached to '{}:{}'", prog_name, category, name);
return Ok(format!("Tracepoint program attached to {}:{}", category, name));
}
}
Err(anyhow!("No Tracepoint program found in eBPF object"))
}

_ => {
// For other program types, just return success since they were loaded
Ok(format!("Program type {} loaded successfully", requirements.program_type))
}
}
}

async fn attach_program_to_kernel(
path: &PathBuf,
requirements: &ProgramRequirements,
Expand Down Expand Up @@ -453,6 +527,7 @@ async fn verify_kernel_attachment(requirements: &ProgramRequirements, opts: &Loa
println!(" {}", line.trim());
}
}
return Err(anyhow!("Failed to verify tracepoint attachment to '{}:{}'", category, name));
}
}

Expand Down
89 changes: 55 additions & 34 deletions eclipta-cli/src/commands/system/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,28 +206,39 @@ async fn get_kernel_status(program_name: &str) -> Result<KernelStatus> {
let mut program_type = None;
let mut memory_usage = None;

for line in stdout.lines() {
if line.contains(program_name) {
loaded = true;

// Extract program ID
if let Some(id_str) = line.split(':').next() {
if let Ok(id) = id_str.parse::<u32>() {
program_id = Some(id);
}
}
// Look for programs loaded by eclipta-cli
// The bpftool output shows function names and pids on different lines
let lines: Vec<&str> = stdout.lines().collect();
for (i, line) in lines.iter().enumerate() {
// Check if this line contains eclipta-cli in the pids field
if line.contains("pids eclipta-cli") {
// Look backwards to find the program info
for j in (0..i).rev() {
let prev_line = lines[j];
if prev_line.contains("tracepoint") || prev_line.contains("xdp") || prev_line.contains("tc") {
loaded = true;

// Extract program ID from the line with the program type
if let Some(id_str) = prev_line.split(':').next() {
if let Ok(id) = id_str.parse::<u32>() {
program_id = Some(id);
}
}

// Extract program type
if let Some(type_part) = line.split_whitespace().nth(1) {
program_type = Some(type_part.to_string());
}
// Extract program type
if let Some(type_part) = prev_line.split_whitespace().nth(1) {
program_type = Some(type_part.to_string());
}

// Extract memory usage
if let Some(mem_part) = line.split("memlock").nth(1) {
if let Some(mem_str) = mem_part.split('B').next() {
if let Ok(mem) = mem_str.parse::<u64>() {
memory_usage = Some(mem);
// Extract memory usage from the current line or nearby
if let Some(mem_part) = line.split("memlock").nth(1) {
if let Some(mem_str) = mem_part.split('B').next() {
if let Ok(mem) = mem_str.parse::<u64>() {
memory_usage = Some(mem);
}
}
}
break;
}
}
break;
Expand Down Expand Up @@ -261,23 +272,33 @@ async fn get_attachment_status(program_name: &str) -> Result<AttachmentStatus> {
let mut target = None;
let mut hook_point = None;

for line in stdout.lines() {
if line.contains(program_name) {
attached = true;

// Extract attachment type
if let Some(type_part) = line.split_whitespace().nth(1) {
attachment_type = Some(type_part.to_string());
}
// Look for eclipta-cli processes with attachments
let lines: Vec<&str> = stdout.lines().collect();
for (i, line) in lines.iter().enumerate() {
// Check if this line contains eclipta-cli in the pids field
if line.contains("pids eclipta-cli") {
// Look backwards to find the attachment info
for j in (0..i).rev() {
let prev_line = lines[j];
if prev_line.contains("tracepoint") || prev_line.contains("perf_event") {
attached = true;

// Extract attachment type
if let Some(type_part) = prev_line.split_whitespace().nth(1) {
attachment_type = Some(type_part.to_string());
}

// Extract target/hook information
if let Some(target_part) = line.split_whitespace().nth(2) {
target = Some(target_part.to_string());
}
// Extract target/hook information
if let Some(target_part) = prev_line.split_whitespace().nth(2) {
target = Some(target_part.to_string());
}

// Extract hook point
if let Some(hook_part) = line.split_whitespace().nth(3) {
hook_point = Some(hook_part.to_string());
// Extract hook point
if let Some(hook_part) = prev_line.split_whitespace().nth(3) {
hook_point = Some(hook_part.to_string());
}
break;
}
}
break;
}
Expand Down