diff --git a/eclipta-cli/src/commands/ebpf/load.rs b/eclipta-cli/src/commands/ebpf/load.rs index e9366b1..f05f2c1 100644 --- a/eclipta-cli/src/commands/ebpf/load.rs +++ b/eclipta-cli/src/commands/ebpf/load.rs @@ -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?; @@ -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 { + 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, @@ -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)); } } diff --git a/eclipta-cli/src/commands/system/status.rs b/eclipta-cli/src/commands/system/status.rs index 12cf885..8025176 100644 --- a/eclipta-cli/src/commands/system/status.rs +++ b/eclipta-cli/src/commands/system/status.rs @@ -206,28 +206,39 @@ async fn get_kernel_status(program_name: &str) -> Result { 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::() { - 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::() { + 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::() { - 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::() { + memory_usage = Some(mem); + } + } } + break; } } break; @@ -261,23 +272,33 @@ async fn get_attachment_status(program_name: &str) -> Result { 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; }