rbpf.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. use core::{mem::size_of, ptr::null_mut, slice::from_raw_parts};
  2. use std::collections::HashMap;
  3. use aya::include_bytes_aligned;
  4. use aya_obj::{generated::bpf_insn, Object, ProgramSection};
  5. #[test]
  6. fn run_with_rbpf() {
  7. let bytes = include_bytes_aligned!("../../../target/bpfel-unknown-none/release/pass");
  8. let object = Object::parse(bytes).unwrap();
  9. assert_eq!(object.programs.len(), 1);
  10. assert!(matches!(
  11. object.programs["pass"].section,
  12. ProgramSection::Xdp { .. }
  13. ));
  14. assert_eq!(object.programs["pass"].section.name(), "pass");
  15. let instructions = &object
  16. .functions
  17. .get(&object.programs["pass"].function_key())
  18. .unwrap()
  19. .instructions;
  20. let data = unsafe {
  21. from_raw_parts(
  22. instructions.as_ptr() as *const u8,
  23. instructions.len() * size_of::<bpf_insn>(),
  24. )
  25. };
  26. // Use rbpf interpreter instead of JIT compiler to ensure platform compatibility.
  27. let vm = rbpf::EbpfVmNoData::new(Some(data)).unwrap();
  28. const XDP_PASS: u64 = 2;
  29. assert_eq!(vm.execute_program().unwrap(), XDP_PASS);
  30. }
  31. static mut MULTIMAP_MAPS: [*mut Vec<u64>; 2] = [null_mut(), null_mut()];
  32. #[test]
  33. fn use_map_with_rbpf() {
  34. let bytes =
  35. include_bytes_aligned!("../../../target/bpfel-unknown-none/release/multimap-btf.bpf.o");
  36. let mut object = Object::parse(bytes).unwrap();
  37. assert_eq!(object.programs.len(), 1);
  38. assert!(matches!(
  39. object.programs["tracepoint"].section,
  40. ProgramSection::TracePoint { .. }
  41. ));
  42. assert_eq!(object.programs["tracepoint"].section.name(), "tracepoint");
  43. // Initialize maps:
  44. // - fd: 0xCAFE00 or 0xCAFE01 (the 0xCAFE00 part is used to distinguish fds from indices),
  45. // - Note that rbpf does not convert fds into real pointers,
  46. // so we keeps the pointers to our maps in MULTIMAP_MAPS, to be used in helpers.
  47. let mut maps = HashMap::new();
  48. let mut map_instances = vec![vec![0u64], vec![0u64]];
  49. for (name, map) in object.maps.iter() {
  50. assert_eq!(map.key_size(), size_of::<u32>() as u32);
  51. assert_eq!(map.value_size(), size_of::<u64>() as u32);
  52. assert_eq!(
  53. map.map_type(),
  54. aya_obj::generated::bpf_map_type::BPF_MAP_TYPE_ARRAY as u32
  55. );
  56. let map_id = if name == "map_1" { 0 } else { 1 };
  57. let fd = map_id as i32 | 0xCAFE00;
  58. maps.insert(name.to_owned(), (fd, map.clone()));
  59. unsafe {
  60. MULTIMAP_MAPS[map_id] = &mut map_instances[map_id] as *mut _;
  61. }
  62. }
  63. let text_sections = object
  64. .functions
  65. .iter()
  66. .map(|((section_index, _), _)| *section_index)
  67. .collect();
  68. object
  69. .relocate_maps(
  70. maps.iter()
  71. .map(|(s, (fd, map))| (s.as_ref() as &str, Some(*fd), map)),
  72. &text_sections,
  73. )
  74. .expect("Relocation failed");
  75. // Actually there is no local function call involved.
  76. object.relocate_calls(&text_sections).unwrap();
  77. // Executes the program
  78. assert_eq!(object.programs.len(), 1);
  79. let instructions = &object
  80. .functions
  81. .get(&object.programs["tracepoint"].function_key())
  82. .unwrap()
  83. .instructions;
  84. let data = unsafe {
  85. from_raw_parts(
  86. instructions.as_ptr() as *const u8,
  87. instructions.len() * size_of::<bpf_insn>(),
  88. )
  89. };
  90. let mut vm = rbpf::EbpfVmNoData::new(Some(data)).unwrap();
  91. vm.register_helper(2, bpf_map_update_elem_multimap)
  92. .expect("Helper failed");
  93. assert_eq!(vm.execute_program().unwrap(), 0);
  94. assert_eq!(map_instances[0][0], 24);
  95. assert_eq!(map_instances[1][0], 42);
  96. unsafe {
  97. MULTIMAP_MAPS[0] = null_mut();
  98. MULTIMAP_MAPS[1] = null_mut();
  99. }
  100. }
  101. fn bpf_map_update_elem_multimap(map: u64, key: u64, value: u64, _: u64, _: u64) -> u64 {
  102. assert!(map == 0xCAFE00 || map == 0xCAFE01);
  103. let key = *unsafe { (key as usize as *const u32).as_ref().unwrap() };
  104. let value = *unsafe { (value as usize as *const u64).as_ref().unwrap() };
  105. assert_eq!(key, 0);
  106. unsafe {
  107. let map_instance = MULTIMAP_MAPS[map as usize & 0xFF].as_mut().unwrap();
  108. map_instance[0] = value;
  109. }
  110. 0
  111. }