From ec0c7c148b315250822f9172e930bbbb05aad59b Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 3 Sep 2025 13:18:46 +1000 Subject: [PATCH] chore(eBPF): minor polish (#10282) Some follow-up polish for the eBPF module: - Changes the cfg's to also include Linux, allowing rust-analyzer to assist with auto-complete etc. - Moves code to sub-modules of `try_handle_turn`, removing the need for making them conditional. - Move all maps to sub-modules to allow for a single place to put comments: In the module documentation at the top. - Removes interface IP learning, these are now configured via env variables. --- rust/relay/ebpf-turn-router/Cargo.toml | 11 +- rust/relay/ebpf-turn-router/src/main.rs | 19 +- .../ebpf-turn-router/src/try_handle_turn.rs | 208 ++++-------------- .../src/{ => try_handle_turn}/channel_data.rs | 0 .../src/try_handle_turn/channel_maps.rs | 65 ++++++ .../src/{ => try_handle_turn}/checksum.rs | 0 .../src/{ => try_handle_turn}/error.rs | 0 .../src/try_handle_turn/interface.rs | 37 ++++ .../src/{ => try_handle_turn}/ref_mut_at.rs | 2 +- .../src/{ => try_handle_turn}/stats.rs | 0 10 files changed, 150 insertions(+), 192 deletions(-) rename rust/relay/ebpf-turn-router/src/{ => try_handle_turn}/channel_data.rs (100%) create mode 100644 rust/relay/ebpf-turn-router/src/try_handle_turn/channel_maps.rs rename rust/relay/ebpf-turn-router/src/{ => try_handle_turn}/checksum.rs (100%) rename rust/relay/ebpf-turn-router/src/{ => try_handle_turn}/error.rs (100%) create mode 100644 rust/relay/ebpf-turn-router/src/try_handle_turn/interface.rs rename rust/relay/ebpf-turn-router/src/{ => try_handle_turn}/ref_mut_at.rs (96%) rename rust/relay/ebpf-turn-router/src/{ => try_handle_turn}/stats.rs (100%) diff --git a/rust/relay/ebpf-turn-router/Cargo.toml b/rust/relay/ebpf-turn-router/Cargo.toml index 249c07c96..30ff21be3 100644 --- a/rust/relay/ebpf-turn-router/Cargo.toml +++ b/rust/relay/ebpf-turn-router/Cargo.toml @@ -4,24 +4,19 @@ version = "0.1.0" edition = { workspace = true } license = { workspace = true } -[package.metadata.cargo-udeps.ignore] -normal = ["aya-ebpf", "aya-log-ebpf", "ebpf-shared", "network-types"] -build = ["which"] -development = ["hex-literal", "ip-packet"] - [[bin]] name = "ebpf-turn-router-main" # This needs to be different from the package name otherwise the build-script fails to differentiate between the directory it is built in and the actual binary. path = "src/main.rs" -[dependencies] +[target.'cfg(any(target_arch = "bpf", target_os = "linux"))'.dependencies] aya-ebpf = { workspace = true } aya-log-ebpf = { workspace = true } ebpf-shared = { workspace = true } network-types = { workspace = true } -[build-dependencies] +[target.'cfg(target_os = "linux")'.build-dependencies] which = { workspace = true } -[dev-dependencies] +[target.'cfg(target_os = "linux")'.dev-dependencies] hex-literal = { workspace = true } ip-packet = { workspace = true } diff --git a/rust/relay/ebpf-turn-router/src/main.rs b/rust/relay/ebpf-turn-router/src/main.rs index 5e7475300..45759db43 100644 --- a/rust/relay/ebpf-turn-router/src/main.rs +++ b/rust/relay/ebpf-turn-router/src/main.rs @@ -9,28 +9,15 @@ fn main() { std::process::exit(1); } -// Include modules only for BPF target -#[cfg(target_arch = "bpf")] -mod channel_data; -#[cfg(target_arch = "bpf")] -mod checksum; -#[cfg(target_arch = "bpf")] -mod error; -#[cfg(target_arch = "bpf")] -mod ref_mut_at; -#[cfg(target_arch = "bpf")] -mod stats; -#[cfg(target_arch = "bpf")] +#[cfg(any(target_arch = "bpf", target_os = "linux"))] mod try_handle_turn; -// Everything below is only for BPF target -#[cfg(target_arch = "bpf")] +#[cfg(any(target_arch = "bpf", target_os = "linux"))] #[aya_ebpf::macros::xdp] -// Per-CPU data structures to learn relay interface addresses pub fn handle_turn(ctx: aya_ebpf::programs::XdpContext) -> u32 { use aya_ebpf::bindings::xdp_action; use aya_log_ebpf::{debug, warn}; - use error::Error; + use try_handle_turn::Error; try_handle_turn::try_handle_turn(&ctx).unwrap_or_else(|e| match e { Error::NotIp | Error::NotUdp => xdp_action::XDP_PASS, diff --git a/rust/relay/ebpf-turn-router/src/try_handle_turn.rs b/rust/relay/ebpf-turn-router/src/try_handle_turn.rs index a8bc657f0..6c1e6ae16 100644 --- a/rust/relay/ebpf-turn-router/src/try_handle_turn.rs +++ b/rust/relay/ebpf-turn-router/src/try_handle_turn.rs @@ -1,68 +1,34 @@ -use crate::channel_data::CdHdr; -use crate::checksum::ChecksumUpdate; -use crate::error::Error; -use crate::error::SupportedChannel; -use crate::ref_mut_at::ref_mut_at; -use aya_ebpf::{ - bindings::xdp_action, - helpers::bpf_xdp_adjust_head, - macros::map, - maps::{HashMap, PerCpuArray}, - programs::XdpContext, -}; +pub use error::Error; + +use aya_ebpf::{bindings::xdp_action, helpers::bpf_xdp_adjust_head, programs::XdpContext}; use aya_log_ebpf::*; -use core::net::{Ipv4Addr, Ipv6Addr}; -use ebpf_shared::{ - ClientAndChannelV4, ClientAndChannelV6, InterfaceAddressV4, InterfaceAddressV6, PortAndPeerV4, - PortAndPeerV6, -}; +use channel_data::CdHdr; +use checksum::ChecksumUpdate; +use ebpf_shared::{ClientAndChannelV4, ClientAndChannelV6, PortAndPeerV4, PortAndPeerV6}; +use error::SupportedChannel; use network_types::{ eth::{EthHdr, EtherType}, ip::{IpProto, Ipv4Hdr, Ipv6Hdr}, udp::UdpHdr, }; +use ref_mut_at::ref_mut_at; -const NUM_ENTRIES: u32 = 0x10000; -const LOWER_PORT: u16 = 49152; // Lower bound for TURN UDP ports -const UPPER_PORT: u16 = 65535; // Upper bound for TURN UDP ports -const CHAN_START: u16 = 0x4000; // Channel number start -const CHAN_END: u16 = 0x7FFF; // Channel number end +mod channel_data; +mod channel_maps; +mod checksum; +mod error; +mod interface; +mod ref_mut_at; +mod stats; -// SAFETY: Testing has shown that these maps are safe to use as long as we aren't -// writing to them from multiple threads at the same time. Since we only update these -// from the single-threaded eventloop in userspace, we are ok. -// See https://github.com/firezone/firezone/issues/10138#issuecomment-3186074350 - -#[map] -static CHAN_TO_UDP_44: HashMap = - HashMap::with_max_entries(NUM_ENTRIES, 0); -#[map] -static UDP_TO_CHAN_44: HashMap = - HashMap::with_max_entries(NUM_ENTRIES, 0); -#[map] -static CHAN_TO_UDP_66: HashMap = - HashMap::with_max_entries(NUM_ENTRIES, 0); -#[map] -static UDP_TO_CHAN_66: HashMap = - HashMap::with_max_entries(NUM_ENTRIES, 0); -#[map] -static CHAN_TO_UDP_46: HashMap = - HashMap::with_max_entries(NUM_ENTRIES, 0); -#[map] -static UDP_TO_CHAN_46: HashMap = - HashMap::with_max_entries(NUM_ENTRIES, 0); -#[map] -static CHAN_TO_UDP_64: HashMap = - HashMap::with_max_entries(NUM_ENTRIES, 0); -#[map] -static UDP_TO_CHAN_64: HashMap = - HashMap::with_max_entries(NUM_ENTRIES, 0); - -// Per-CPU data structures to learn relay interface addresses -#[map] -static INT_ADDR_V4: PerCpuArray = PerCpuArray::with_max_entries(1, 0); -#[map] -static INT_ADDR_V6: PerCpuArray = PerCpuArray::with_max_entries(1, 0); +/// Lower bound for TURN UDP ports +const LOWER_PORT: u16 = 49152; +/// Upper bound for TURN UDP ports +const UPPER_PORT: u16 = 65535; +/// Channel number start +const CHAN_START: u16 = 0x4000; +/// Channel number end +const CHAN_END: u16 = 0x7FFF; #[inline(always)] pub fn try_handle_turn(ctx: &XdpContext) -> Result { @@ -84,8 +50,6 @@ fn try_handle_turn_ipv4(ctx: &XdpContext) -> Result<(), Error> { // SAFETY: The offset must point to the start of a valid `Ipv4Hdr`. let ipv4 = unsafe { ref_mut_at::(ctx, EthHdr::LEN)? }; - learn_interface_ipv4_address(ipv4)?; - if ipv4.proto != IpProto::Udp { return Err(Error::NotUdp); } @@ -111,14 +75,14 @@ fn try_handle_turn_ipv4(ctx: &XdpContext) -> Result<(), Error> { if (LOWER_PORT..=UPPER_PORT).contains(&udp.dest()) { try_handle_ipv4_udp_to_channel_data(ctx)?; - crate::stats::emit_data_relayed(ctx, udp_payload_len); + stats::emit_data_relayed(ctx, udp_payload_len); return Ok(()); } if udp.dest() == 3478 { try_handle_ipv4_channel_data_to_udp(ctx)?; - crate::stats::emit_data_relayed(ctx, udp_payload_len - CdHdr::LEN as u16); + stats::emit_data_relayed(ctx, udp_payload_len - CdHdr::LEN as u16); return Ok(()); } @@ -131,8 +95,6 @@ fn try_handle_turn_ipv6(ctx: &XdpContext) -> Result<(), Error> { // SAFETY: The offset must point to the start of a valid `Ipv6Hdr`. let ipv6 = unsafe { ref_mut_at::(ctx, EthHdr::LEN)? }; - learn_interface_ipv6_address(ipv6)?; - if ipv6.next_hdr != IpProto::Udp { return Err(Error::NotUdp); } @@ -153,14 +115,14 @@ fn try_handle_turn_ipv6(ctx: &XdpContext) -> Result<(), Error> { if (LOWER_PORT..=UPPER_PORT).contains(&udp.dest()) { try_handle_ipv6_udp_to_channel_data(ctx)?; - crate::stats::emit_data_relayed(ctx, udp_payload_len); + stats::emit_data_relayed(ctx, udp_payload_len); return Ok(()); } if udp.dest() == 3478 { try_handle_ipv6_channel_data_to_udp(ctx)?; - crate::stats::emit_data_relayed(ctx, udp_payload_len - CdHdr::LEN as u16); + stats::emit_data_relayed(ctx, udp_payload_len - CdHdr::LEN as u16); return Ok(()); } @@ -168,42 +130,6 @@ fn try_handle_turn_ipv6(ctx: &XdpContext) -> Result<(), Error> { Err(Error::NotTurn) } -#[inline(always)] -fn learn_interface_ipv4_address(ipv4: &Ipv4Hdr) -> Result<(), Error> { - let interface_addr = INT_ADDR_V4 - .get_ptr_mut(0) - .ok_or(Error::InterfaceIpv4AddressAccessFailed)?; - - let dst_ip = ipv4.dst_addr(); - - // SAFETY: These are per-cpu maps so we don't need to worry about thread safety. - unsafe { - if (*interface_addr).get().is_none() { - (*interface_addr).set(dst_ip); - } - } - - Ok(()) -} - -#[inline(always)] -fn learn_interface_ipv6_address(ipv6: &Ipv6Hdr) -> Result<(), Error> { - let interface_addr = INT_ADDR_V6 - .get_ptr_mut(0) - .ok_or(Error::InterfaceIpv6AddressAccessFailed)?; - - let dst_ip = ipv6.dst_addr(); - - // SAFETY: These are per-cpu maps so we don't need to worry about thread safety. - unsafe { - if (*interface_addr).get().is_none() { - (*interface_addr).set(dst_ip); - } - } - - Ok(()) -} - #[inline(always)] fn try_handle_ipv4_udp_to_channel_data(ctx: &XdpContext) -> Result<(), Error> { // SAFETY: The offset must point to the start of a valid `Ipv4Hdr`. @@ -215,13 +141,13 @@ fn try_handle_ipv4_udp_to_channel_data(ctx: &XdpContext) -> Result<(), Error> { let key = PortAndPeerV4::new(ipv4.src_addr(), udp.dest(), udp.source()); // SAFETY: We only write to these using a single thread in userspace. - if let Some(client_and_channel) = unsafe { UDP_TO_CHAN_44.get(&key) } { + if let Some(client_and_channel) = unsafe { channel_maps::UDP_TO_CHAN_44.get(&key) } { handle_ipv4_udp_to_ipv4_channel(ctx, client_and_channel)?; return Ok(()); } // SAFETY: We only write to these using a single thread in userspace. - if let Some(client_and_channel) = unsafe { UDP_TO_CHAN_46.get(&key) } { + if let Some(client_and_channel) = unsafe { channel_maps::UDP_TO_CHAN_46.get(&key) } { handle_ipv4_udp_to_ipv6_channel(ctx, client_and_channel)?; return Ok(()); } @@ -257,14 +183,14 @@ fn try_handle_ipv4_channel_data_to_udp(ctx: &XdpContext) -> Result<(), Error> { let key = ClientAndChannelV4::new(ipv4.src_addr(), udp.source(), channel_number); // SAFETY: We only write to these using a single thread in userspace. - if let Some(port_and_peer) = unsafe { CHAN_TO_UDP_44.get(&key) } { + if let Some(port_and_peer) = unsafe { channel_maps::CHAN_TO_UDP_44.get(&key) } { // IPv4 to IPv4 - existing logic handle_ipv4_channel_to_ipv4_udp(ctx, port_and_peer)?; return Ok(()); } // SAFETY: We only write to these using a single thread in userspace. - if let Some(port_and_peer) = unsafe { CHAN_TO_UDP_46.get(&key) } { + if let Some(port_and_peer) = unsafe { channel_maps::CHAN_TO_UDP_46.get(&key) } { handle_ipv4_channel_to_ipv6_udp(ctx, port_and_peer)?; return Ok(()); } @@ -283,13 +209,13 @@ fn try_handle_ipv6_udp_to_channel_data(ctx: &XdpContext) -> Result<(), Error> { let key = PortAndPeerV6::new(ipv6.src_addr(), udp.dest(), udp.source()); // SAFETY: We only write to these using a single thread in userspace. - if let Some(client_and_channel) = unsafe { UDP_TO_CHAN_66.get(&key) } { + if let Some(client_and_channel) = unsafe { channel_maps::UDP_TO_CHAN_66.get(&key) } { handle_ipv6_udp_to_ipv6_channel(ctx, client_and_channel)?; return Ok(()); } // SAFETY: We only write to these using a single thread in userspace. - if let Some(client_and_channel) = unsafe { UDP_TO_CHAN_64.get(&key) } { + if let Some(client_and_channel) = unsafe { channel_maps::UDP_TO_CHAN_64.get(&key) } { handle_ipv6_udp_to_ipv4_channel(ctx, client_and_channel)?; return Ok(()); } @@ -325,13 +251,13 @@ fn try_handle_ipv6_channel_data_to_udp(ctx: &XdpContext) -> Result<(), Error> { let key = ClientAndChannelV6::new(ipv6.src_addr(), udp.source(), u16::from_be_bytes(cd.number)); // SAFETY: We only write to these using a single thread in userspace. - if let Some(port_and_peer) = unsafe { CHAN_TO_UDP_66.get(&key) } { + if let Some(port_and_peer) = unsafe { channel_maps::CHAN_TO_UDP_66.get(&key) } { handle_ipv6_channel_to_ipv6_udp(ctx, port_and_peer)?; return Ok(()); } // SAFETY: We only write to these using a single thread in userspace. - if let Some(port_and_peer) = unsafe { CHAN_TO_UDP_64.get(&key) } { + if let Some(port_and_peer) = unsafe { channel_maps::CHAN_TO_UDP_64.get(&key) } { handle_ipv6_channel_to_ipv4_udp(ctx, port_and_peer)?; return Ok(()); } @@ -556,7 +482,7 @@ fn handle_ipv4_udp_to_ipv6_channel( // 2. IPv4 -> IPv6 header // - let new_ipv6_src = get_interface_ipv6_address()?; + let new_ipv6_src = interface::ipv6_address()?; let new_ipv6_dst = client_and_channel.client_ip(); let new_ipv6_len = old_ipv4_len - Ipv4Hdr::LEN as u16 + CdHdr::LEN as u16; @@ -850,7 +776,7 @@ fn handle_ipv4_channel_to_ipv6_udp( // 2. IPv6 header // - let new_ipv6_src = get_interface_ipv6_address()?; + let new_ipv6_src = interface::ipv6_address()?; let new_ipv6_dst = port_and_peer.peer_ip(); let new_udp_len = old_udp_len - CdHdr::LEN as u16; @@ -1094,7 +1020,7 @@ fn handle_ipv6_udp_to_ipv4_channel( // 2. IPv6 -> IPv4 header // - let new_ipv4_src = get_interface_ipv4_address()?; + let new_ipv4_src = interface::ipv4_address()?; let new_ipv4_dst = client_and_channel.client_ip(); let new_udp_len = old_udp_len + CdHdr::LEN as u16; let new_ipv4_len = Ipv4Hdr::LEN as u16 + new_udp_len; @@ -1118,7 +1044,7 @@ fn handle_ipv6_udp_to_ipv4_channel( ipv4.set_dst_addr(new_ipv4_dst); // Calculate fresh checksum - let check = crate::checksum::new_ipv4(ipv4); + let check = checksum::new_ipv4(ipv4); ipv4.set_checksum(check); // @@ -1366,7 +1292,7 @@ fn handle_ipv6_channel_to_ipv4_udp( // 2. IPv6 -> IPv4 header // - let new_ipv4_src = get_interface_ipv4_address()?; + let new_ipv4_src = interface::ipv4_address()?; let new_ipv4_dst = port_and_peer.peer_ip(); let new_ipv4_len = old_udp_len - CdHdr::LEN as u16 + Ipv4Hdr::LEN as u16; @@ -1389,7 +1315,7 @@ fn handle_ipv6_channel_to_ipv4_udp( ipv4.set_dst_addr(new_ipv4_dst); // Calculate fresh checksum - let check = crate::checksum::new_ipv4(ipv4); + let check = checksum::new_ipv4(ipv4); ipv4.set_checksum(check); // @@ -1443,55 +1369,3 @@ fn adjust_head(ctx: &XdpContext, size: i32) -> Result<(), Error> { Ok(()) } - -#[inline(always)] -fn get_interface_ipv4_address() -> Result { - let interface_addr = INT_ADDR_V4 - .get_ptr_mut(0) - .ok_or(Error::InterfaceIpv4AddressAccessFailed)?; - - // SAFETY: This comes from a per-cpu data structure so we can safely access it. - let addr = unsafe { *interface_addr }; - - addr.get().ok_or(Error::InterfaceIpv4AddressNotConfigured) -} - -fn get_interface_ipv6_address() -> Result { - let interface_addr = INT_ADDR_V6 - .get_ptr_mut(0) - .ok_or(Error::InterfaceIpv6AddressAccessFailed)?; - - // SAFETY: This comes from a per-cpu data structure so we can safely access it. - let addr = unsafe { *interface_addr }; - - addr.get().ok_or(Error::InterfaceIpv6AddressNotConfigured) -} - -#[cfg(test)] -mod tests { - use super::*; - - /// Memory overhead of an eBPF map. - /// - /// Determined empirically. - const HASH_MAP_OVERHEAD: f32 = 1.5; - - #[test] - fn hashmaps_are_less_than_11_mb() { - let ipv4_datatypes = - core::mem::size_of::() + core::mem::size_of::(); - let ipv6_datatypes = - core::mem::size_of::() + core::mem::size_of::(); - - let ipv4_map_size = ipv4_datatypes as f32 * NUM_ENTRIES as f32 * HASH_MAP_OVERHEAD; - let ipv6_map_size = ipv6_datatypes as f32 * NUM_ENTRIES as f32 * HASH_MAP_OVERHEAD; - - let total_map_size = (ipv4_map_size + ipv6_map_size) * 2_f32; - let total_map_size_mb = total_map_size / 1024_f32 / 1024_f32; - - assert!( - total_map_size_mb < 11_f32, - "Total map size = {total_map_size_mb} MB" - ); - } -} diff --git a/rust/relay/ebpf-turn-router/src/channel_data.rs b/rust/relay/ebpf-turn-router/src/try_handle_turn/channel_data.rs similarity index 100% rename from rust/relay/ebpf-turn-router/src/channel_data.rs rename to rust/relay/ebpf-turn-router/src/try_handle_turn/channel_data.rs diff --git a/rust/relay/ebpf-turn-router/src/try_handle_turn/channel_maps.rs b/rust/relay/ebpf-turn-router/src/try_handle_turn/channel_maps.rs new file mode 100644 index 000000000..1f2fd35d9 --- /dev/null +++ b/rust/relay/ebpf-turn-router/src/try_handle_turn/channel_maps.rs @@ -0,0 +1,65 @@ +//! Houses all combinations of IPv4 <> IPv6 and Channel <> UDP mappings. +//! +//! Testing has shown that these maps are safe to use as long as we aren't +//! writing to them from multiple threads at the same time. Since we only update these +//! from the single-threaded eventloop in userspace, we are ok. +//! See . + +use aya_ebpf::{macros::map, maps::HashMap}; +use ebpf_shared::{ClientAndChannelV4, ClientAndChannelV6, PortAndPeerV4, PortAndPeerV6}; + +const NUM_ENTRIES: u32 = 0x10000; + +#[map] +pub static CHAN_TO_UDP_44: HashMap = + HashMap::with_max_entries(NUM_ENTRIES, 0); +#[map] +pub static UDP_TO_CHAN_44: HashMap = + HashMap::with_max_entries(NUM_ENTRIES, 0); +#[map] +pub static CHAN_TO_UDP_66: HashMap = + HashMap::with_max_entries(NUM_ENTRIES, 0); +#[map] +pub static UDP_TO_CHAN_66: HashMap = + HashMap::with_max_entries(NUM_ENTRIES, 0); +#[map] +pub static CHAN_TO_UDP_46: HashMap = + HashMap::with_max_entries(NUM_ENTRIES, 0); +#[map] +pub static UDP_TO_CHAN_46: HashMap = + HashMap::with_max_entries(NUM_ENTRIES, 0); +#[map] +pub static CHAN_TO_UDP_64: HashMap = + HashMap::with_max_entries(NUM_ENTRIES, 0); +#[map] +pub static UDP_TO_CHAN_64: HashMap = + HashMap::with_max_entries(NUM_ENTRIES, 0); + +#[cfg(test)] +mod tests { + use super::*; + + /// Memory overhead of an eBPF map. + /// + /// Determined empirically. + const HASH_MAP_OVERHEAD: f32 = 1.5; + + #[test] + fn hashmaps_are_less_than_11_mb() { + let ipv4_datatypes = + core::mem::size_of::() + core::mem::size_of::(); + let ipv6_datatypes = + core::mem::size_of::() + core::mem::size_of::(); + + let ipv4_map_size = ipv4_datatypes as f32 * NUM_ENTRIES as f32 * HASH_MAP_OVERHEAD; + let ipv6_map_size = ipv6_datatypes as f32 * NUM_ENTRIES as f32 * HASH_MAP_OVERHEAD; + + let total_map_size = (ipv4_map_size + ipv6_map_size) * 2_f32; + let total_map_size_mb = total_map_size / 1024_f32 / 1024_f32; + + assert!( + total_map_size_mb < 11_f32, + "Total map size = {total_map_size_mb} MB" + ); + } +} diff --git a/rust/relay/ebpf-turn-router/src/checksum.rs b/rust/relay/ebpf-turn-router/src/try_handle_turn/checksum.rs similarity index 100% rename from rust/relay/ebpf-turn-router/src/checksum.rs rename to rust/relay/ebpf-turn-router/src/try_handle_turn/checksum.rs diff --git a/rust/relay/ebpf-turn-router/src/error.rs b/rust/relay/ebpf-turn-router/src/try_handle_turn/error.rs similarity index 100% rename from rust/relay/ebpf-turn-router/src/error.rs rename to rust/relay/ebpf-turn-router/src/try_handle_turn/error.rs diff --git a/rust/relay/ebpf-turn-router/src/try_handle_turn/interface.rs b/rust/relay/ebpf-turn-router/src/try_handle_turn/interface.rs new file mode 100644 index 000000000..3df7a6139 --- /dev/null +++ b/rust/relay/ebpf-turn-router/src/try_handle_turn/interface.rs @@ -0,0 +1,37 @@ +//! Per-CPU data structures to store relay interface addresses. + +use core::net::{Ipv4Addr, Ipv6Addr}; + +use aya_ebpf::{macros::map, maps::PerCpuArray}; +use ebpf_shared::{InterfaceAddressV4, InterfaceAddressV6}; + +use crate::try_handle_turn::Error; + +#[map] +static INT_ADDR_V4: PerCpuArray = PerCpuArray::with_max_entries(1, 0); +#[map] +static INT_ADDR_V6: PerCpuArray = PerCpuArray::with_max_entries(1, 0); + +#[inline(always)] +pub fn ipv4_address() -> Result { + let interface_addr = INT_ADDR_V4 + .get_ptr_mut(0) + .ok_or(Error::InterfaceIpv4AddressAccessFailed)?; + + // SAFETY: This comes from a per-cpu data structure so we can safely access it. + let addr = unsafe { *interface_addr }; + + addr.get().ok_or(Error::InterfaceIpv4AddressNotConfigured) +} + +#[inline(always)] +pub fn ipv6_address() -> Result { + let interface_addr = INT_ADDR_V6 + .get_ptr_mut(0) + .ok_or(Error::InterfaceIpv6AddressAccessFailed)?; + + // SAFETY: This comes from a per-cpu data structure so we can safely access it. + let addr = unsafe { *interface_addr }; + + addr.get().ok_or(Error::InterfaceIpv6AddressNotConfigured) +} diff --git a/rust/relay/ebpf-turn-router/src/ref_mut_at.rs b/rust/relay/ebpf-turn-router/src/try_handle_turn/ref_mut_at.rs similarity index 96% rename from rust/relay/ebpf-turn-router/src/ref_mut_at.rs rename to rust/relay/ebpf-turn-router/src/try_handle_turn/ref_mut_at.rs index 5e37b0c40..72e80f4f8 100644 --- a/rust/relay/ebpf-turn-router/src/ref_mut_at.rs +++ b/rust/relay/ebpf-turn-router/src/try_handle_turn/ref_mut_at.rs @@ -1,6 +1,6 @@ use aya_ebpf::programs::XdpContext; -use crate::error::Error; +use crate::try_handle_turn::Error; /// Returns a mutable reference to a type `T` at the specified offset in the packet data. /// diff --git a/rust/relay/ebpf-turn-router/src/stats.rs b/rust/relay/ebpf-turn-router/src/try_handle_turn/stats.rs similarity index 100% rename from rust/relay/ebpf-turn-router/src/stats.rs rename to rust/relay/ebpf-turn-router/src/try_handle_turn/stats.rs