Skip to content

Commit c8dbafd

Browse files
committed
vey-daemon: enable ebpf with ListenUdpRuntime
1 parent adaaaea commit c8dbafd

12 files changed

Lines changed: 89 additions & 30 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/vey-daemon/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@ libc.workspace = true
5353

5454
[target.'cfg(target_os = "linux")'.dependencies]
5555
vey-journal.workspace = true
56+
vey-reuseport = { workspace = true, optional = true }
5657

5758
[features]
5859
default = []
5960
jemalloc = ["dep:vey-jemalloc"]
61+
ebpf = ["dep:vey-reuseport"]
6062
event-log = ["dep:vey-fluentd"]
6163
register = ["vey-yaml/http", "dep:http", "dep:serde_json", "dep:vey-http"]
6264
quic = ["dep:quinn", "vey-types/acl-rule"]

lib/vey-daemon/src/control/quit.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ impl<T: QuitAction> QuitLoop<T> {
131131
Ok(None) => break 'outer,
132132
Err(_) => {
133133
if is_restart {
134-
// the new process may be failed to start, so we consume
134+
// the new process may be failed to start, so we resume
135135
info!(
136136
"timeout to wait StartGracefulShutdown request, will resume"
137137
);
@@ -140,7 +140,7 @@ impl<T: QuitAction> QuitLoop<T> {
140140
continue 'outer;
141141
} else {
142142
// treat timeout to stop
143-
info!("timeout to wait new request, will stop");
143+
info!("timeout to wait new controller request, will stop");
144144
self.release_controller().await;
145145
break;
146146
}

lib/vey-daemon/src/listen/udp/listen.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use std::collections::VecDeque;
1616
use std::future::poll_fn;
1717
use std::io::{self, IoSlice, IoSliceMut};
1818
use std::net::SocketAddr;
19+
#[cfg(all(target_os = "linux", feature = "ebpf"))]
20+
use std::os::fd::AsRawFd;
1921
use std::pin::Pin;
2022
use std::sync::Arc;
2123
use std::sync::atomic::{AtomicUsize, Ordering};
@@ -33,6 +35,9 @@ use tokio::sync::{broadcast, mpsc};
3335

3436
use vey_io_ext::{UdpMoveRecv, UdpMoveSend, UdpSocketExt};
3537
use vey_io_sys::udp::{RecvMsgHdr, SendMsgHdr};
38+
#[cfg(all(target_os = "linux", feature = "ebpf"))]
39+
use vey_reuseport::udp::UdpSocketSelector;
40+
use vey_std_ext::core::NonZeroExt;
3641
use vey_types::net::{UdpConnectionTrackConfig, UdpListenConfig};
3742

3843
use crate::listen::{ListenAliveGuard, ListenStats};
@@ -511,11 +516,21 @@ where
511516
}
512517
}
513518

519+
#[cfg(all(target_os = "linux", feature = "ebpf"))]
520+
let mut udp_reuseport_selector = UdpSocketSelector::new(
521+
rustix::process::getpid().as_raw_pid(),
522+
self.server.version() as u32,
523+
listen_config.address(),
524+
self.conn_track.max_sessions(),
525+
)?;
526+
514527
for i in 0..instance_count {
515528
let mut runtime = self.create_instance();
516529
runtime.instance_id = i;
517530

518531
let socket = vey_socket::udp::new_std_bind_listen(listen_config)?;
532+
#[cfg(all(target_os = "linux", feature = "ebpf"))]
533+
udp_reuseport_selector.add_socket(socket.as_raw_fd());
519534
let listen_addr = socket.local_addr()?;
520535
runtime.into_running(
521536
socket,
@@ -524,6 +539,21 @@ where
524539
server_reload_sender.subscribe(),
525540
);
526541
}
542+
543+
#[cfg(all(target_os = "linux", feature = "ebpf"))]
544+
{
545+
udp_reuseport_selector.load_and_attach()?;
546+
let mut server_reload_receiver = server_reload_sender.subscribe();
547+
tokio::spawn(async move {
548+
while let Ok(cmd) = server_reload_receiver.recv().await {
549+
if matches!(cmd, ServerReloadCommand::QuitRuntime) {
550+
break;
551+
}
552+
}
553+
drop(udp_reuseport_selector);
554+
});
555+
}
556+
527557
Ok(())
528558
}
529559
}
@@ -604,8 +634,10 @@ where
604634
) {
605635
use broadcast::error::RecvError;
606636

607-
let mut ct_table =
608-
LruCache::with_hasher(self.conn_track.max_sessions(), FixedState::with_seed(0));
637+
let mut ct_table = LruCache::with_hasher(
638+
self.conn_track.max_sessions().cast_usize(),
639+
FixedState::with_seed(0),
640+
);
609641
let mut rt_state = RuntimeState::new(socket, self.conn_track.send_queue_size());
610642

611643
let mut event_recv_buf: Vec<Event> = Vec::with_capacity(EVENT_RECV_BATCH_SIZE);

lib/vey-reuseport/src/bin/udp_reuseport_test.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use std::fs;
77
use std::io;
88
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
9+
use std::num::NonZeroU32;
910
use std::os::fd::AsRawFd;
1011
use std::thread;
1112
use std::time::Duration;
@@ -38,6 +39,8 @@ fn main() -> anyhow::Result<()> {
3839
println!(" UdpSocketSelector Hot-Upgrade & Fallback Test ");
3940
println!("==================================================");
4041

42+
let max_entries = NonZeroU32::new(1024).unwrap();
43+
4144
// 1. Check root privileges
4245
if unsafe { libc::getuid() } != 0 {
4346
println!("[ERROR] This test case must be run as root to load eBPF programs and pin maps.");
@@ -61,8 +64,8 @@ fn main() -> anyhow::Result<()> {
6164
);
6265

6366
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port);
64-
let mut selector_gen1 =
65-
UdpSocketSelector::new(1234, 1, addr, 1024).context("failed to create Gen 1 selector")?;
67+
let mut selector_gen1 = UdpSocketSelector::new(1234, 1, addr, max_entries)
68+
.context("failed to create Gen 1 selector")?;
6669
selector_gen1.add_socket(s1_gen1.as_raw_fd());
6770
selector_gen1.add_socket(s2_gen1.as_raw_fd());
6871

@@ -116,8 +119,8 @@ fn main() -> anyhow::Result<()> {
116119
s2_gen2.as_raw_fd()
117120
);
118121

119-
let mut selector_gen2 =
120-
UdpSocketSelector::new(1234, 2, addr, 1024).context("failed to create Gen 2 selector")?;
122+
let mut selector_gen2 = UdpSocketSelector::new(1234, 2, addr, max_entries)
123+
.context("failed to create Gen 2 selector")?;
121124
selector_gen2.add_socket(s1_gen2.as_raw_fd());
122125
selector_gen2.add_socket(s2_gen2.as_raw_fd());
123126

lib/vey-reuseport/src/bpf/udp.bpf.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
#include <linux/bpf.h>
55
#include <bpf/bpf_helpers.h>
66

7-
const volatile __u32 load_pid = 0;
7+
const volatile __s32 load_pid = 0;
88
const volatile __u32 load_generation = 0;
99

1010
struct socket_id {
11-
__u32 pid;
11+
__s32 pid;
1212
__u32 generation;
1313
__u32 worker;
1414
};
@@ -22,7 +22,7 @@ struct {
2222
} conn_track SEC(".maps");
2323

2424
struct proc_info_key {
25-
__u32 pid;
25+
__s32 pid;
2626
__u32 generation;
2727
};
2828

lib/vey-reuseport/src/udp.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
use std::io;
77
use std::net::{IpAddr, SocketAddr};
8+
use std::num::NonZeroU32;
89
use std::os::fd::AsFd;
910
use std::os::unix::io::{AsRawFd, RawFd};
1011
use std::path::{Path, PathBuf};
@@ -25,15 +26,15 @@ const NAME_PROGRAM: &str = "udp_select_reuseport";
2526
#[derive(IntoBytes, Immutable)]
2627
#[repr(C)]
2728
struct SocketId {
28-
pid: u32,
29+
pid: i32,
2930
generation: u32,
3031
worker: u32,
3132
}
3233

3334
#[derive(IntoBytes, Immutable)]
3435
#[repr(C)]
3536
struct ProcMapKey {
36-
pid: u32,
37+
pid: i32,
3738
generation: u32,
3839
}
3940

@@ -45,14 +46,14 @@ struct ProcMapValue {
4546
}
4647

4748
struct ReadOnlyData {
48-
load_pid: u32,
49+
load_pid: i32,
4950
load_generation: u32,
5051
}
5152

5253
pub struct UdpSocketSelector {
5354
pin_dir: PathBuf,
54-
conn_track_max_entries: u32,
55-
pid: u32,
55+
conn_track_max_entries: NonZeroU32,
56+
pid: i32,
5657
generation: u32,
5758
sockets: Vec<RawFd>,
5859
proc_map_handle: Option<MapHandle>,
@@ -65,10 +66,10 @@ impl UdpSocketSelector {
6566
}
6667

6768
pub fn new(
68-
pid: u32,
69+
pid: i32,
6970
generation: u32,
7071
addr: SocketAddr,
71-
conn_track_max_entries: u32,
72+
conn_track_max_entries: NonZeroU32,
7273
) -> anyhow::Result<Self> {
7374
let ip = match addr.ip() {
7475
IpAddr::V4(ip) => ip.to_ipv6_compatible(), // IPv4 "." is not allowed in path
@@ -148,8 +149,9 @@ impl UdpSocketSelector {
148149
};
149150
match name {
150151
NAME_CONN_TRACK => {
152+
let max_entries = self.conn_track_max_entries.get();
151153
if let Ok(handle) = MapHandle::from_pinned_path(&conn_track_path) {
152-
if handle.max_entries() != self.conn_track_max_entries {
154+
if handle.max_entries() != max_entries {
153155
warn!(
154156
"udp conn_track map {} already pinned with max entries {}, delete it first if you want to set max entries to {}",
155157
conn_track_path.display(),
@@ -165,10 +167,9 @@ impl UdpSocketSelector {
165167
)
166168
})?;
167169
} else {
168-
map.set_max_entries(self.conn_track_max_entries)
169-
.map_err(|e| {
170-
anyhow!("failed to set max entries for conn_track map: {e}")
171-
})?;
170+
map.set_max_entries(max_entries).map_err(|e| {
171+
anyhow!("failed to set max entries for conn_track map: {e}")
172+
})?;
172173
}
173174
}
174175
NAME_SOCKET_MAP => {

lib/vey-std-ext/src/core/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ pub use option::OptionExt;
88

99
mod zig_zag;
1010
pub use zig_zag::{FromZigZag, ToZigZag};
11+
12+
mod non_zero;
13+
pub use non_zero::NonZeroExt;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* SPDX-FileCopyrightText: 2026 VEY-OSS Developers.
4+
*/
5+
6+
use std::num::{NonZeroU32, NonZeroUsize};
7+
8+
pub trait NonZeroExt {
9+
fn cast_usize(&self) -> NonZeroUsize;
10+
}
11+
12+
impl NonZeroExt for NonZeroU32 {
13+
fn cast_usize(&self) -> NonZeroUsize {
14+
let v = self.get();
15+
unsafe { NonZeroUsize::new_unchecked(v as usize) }
16+
}
17+
}

lib/vey-types/src/net/udp/listen.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
use std::net::{IpAddr, Ipv6Addr, SocketAddr};
8-
use std::num::NonZeroUsize;
8+
use std::num::{NonZeroU32, NonZeroUsize};
99

1010
use anyhow::anyhow;
1111
use num_traits::ToPrimitive;
@@ -204,7 +204,7 @@ impl UdpListenConfig {
204204

205205
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
206206
pub struct UdpConnectionTrackConfig {
207-
max_sessions: NonZeroUsize,
207+
max_sessions: NonZeroU32,
208208
dispatch_queue_size: NonZeroUsize,
209209
send_queue_size: NonZeroUsize,
210210
batch_recv_size: NonZeroUsize,
@@ -213,7 +213,7 @@ pub struct UdpConnectionTrackConfig {
213213
impl Default for UdpConnectionTrackConfig {
214214
fn default() -> Self {
215215
UdpConnectionTrackConfig {
216-
max_sessions: unsafe { NonZeroUsize::new_unchecked(4096) },
216+
max_sessions: unsafe { NonZeroU32::new_unchecked(32768) },
217217
dispatch_queue_size: unsafe { NonZeroUsize::new_unchecked(32) },
218218
send_queue_size: unsafe { NonZeroUsize::new_unchecked(512) },
219219
batch_recv_size: unsafe { NonZeroUsize::new_unchecked(16) },
@@ -223,12 +223,12 @@ impl Default for UdpConnectionTrackConfig {
223223

224224
impl UdpConnectionTrackConfig {
225225
#[inline]
226-
pub fn max_sessions(&self) -> NonZeroUsize {
226+
pub fn max_sessions(&self) -> NonZeroU32 {
227227
self.max_sessions
228228
}
229229

230230
#[inline]
231-
pub fn set_max_sessions(&mut self, max_sessions: NonZeroUsize) {
231+
pub fn set_max_sessions(&mut self, max_sessions: NonZeroU32) {
232232
self.max_sessions = max_sessions;
233233
}
234234

0 commit comments

Comments
 (0)