From 53a174bf16f8a57a8a1b594d0bc500e8d73de751 Mon Sep 17 00:00:00 2001 From: Junho Choi Date: Thu, 1 Jul 2021 15:43:05 -0700 Subject: [PATCH] quiche-server: sendmmsg() support when supported. --- tools/apps/src/bin/quiche-server.rs | 3 + tools/apps/src/sendto.rs | 90 ++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/tools/apps/src/bin/quiche-server.rs b/tools/apps/src/bin/quiche-server.rs index e7d88282cf..b04077facc 100644 --- a/tools/apps/src/bin/quiche-server.rs +++ b/tools/apps/src/bin/quiche-server.rs @@ -86,8 +86,10 @@ fn main() { let max_datagram_size = MAX_DATAGRAM_SIZE; let enable_gso = detect_gso(&socket, max_datagram_size); + let enable_sendmmsg = detect_sendmmsg(); trace!("GSO detected: {}", enable_gso); + trace!("sendmmsg() detected: {}", enable_sendmmsg); // Create the configuration for the QUIC connections. let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap(); @@ -522,6 +524,7 @@ fn main() { &dst_info.unwrap().to, client.max_datagram_size, enable_gso, + enable_sendmmsg, ) { if e.kind() == std::io::ErrorKind::WouldBlock { trace!("send() would block"); diff --git a/tools/apps/src/sendto.rs b/tools/apps/src/sendto.rs index da7a8ba20c..059bd09fd7 100644 --- a/tools/apps/src/sendto.rs +++ b/tools/apps/src/sendto.rs @@ -92,12 +92,89 @@ fn send_to_gso( panic!("send_to_gso() should not be called on non-linux platforms"); } +/// Detecting whether sendmmsg() can be used. +pub fn detect_sendmmsg() -> bool { + cfg!(target_os = "linux") || + cfg!(target_os = "android") || + cfg!(target_os = "freebsd") || + cfg!(target_os = "netbsd") +} + +/// Send packets using sendmmsg(). +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +))] +fn send_to_sendmmsg( + socket: &mio::net::UdpSocket, buf: &[u8], target: &net::SocketAddr, + segment_size: usize, +) -> io::Result { + use nix::sys::socket::sendmmsg; + use nix::sys::socket::InetAddr; + use nix::sys::socket::MsgFlags; + use nix::sys::socket::SendMmsgData; + use nix::sys::socket::SockAddr; + use nix::sys::uio::IoVec; + use std::os::unix::io::AsRawFd; + + let dst = SockAddr::new_inet(InetAddr::from_std(target)); + + let mut off = 0; + let mut left = buf.len(); + + let mut msgs = Vec::new(); + let mut iovs = Vec::new(); + + while left > 0 { + let pkt_len = cmp::min(left, segment_size); + + iovs.push([IoVec::from_slice(&buf[off..off + pkt_len])]); + + off += pkt_len; + left -= pkt_len; + } + + for iov in iovs.iter() { + msgs.push(SendMmsgData { + iov, + cmsgs: &[], + addr: Some(dst), + _lt: Default::default(), + }); + } + + match sendmmsg(socket.as_raw_fd(), msgs.iter(), MsgFlags::empty()) { + Ok(results) => Ok(results.iter().sum()), + Err(e) => match e.as_errno() { + Some(v) => Err(io::Error::from(v)), + None => Err(io::Error::new(io::ErrorKind::Other, e)), + }, + } +} + +/// Send packets using sendmmsg(). +#[cfg(not(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "netbsd", +)))] +fn send_to_sendmmsg( + _socket: &mio::net::UdpSocket, _buf: &[u8], _target: &net::SocketAddr, + _segment_size: usize, +) -> io::Result { + panic!("send_to_sendmmsg() should not be called on non-supported platforms"); +} + /// A wrapper function of send_to(). /// - when GSO enabled, send a packet using send_to_gso(). +/// - when sendmmsg() enabled, send a packet using send_to_sendmmsg(). /// Otherwise, send packet using socket.send_to(). pub fn send_to( socket: &mio::net::UdpSocket, buf: &[u8], target: &net::SocketAddr, - segment_size: usize, enable_gso: bool, + segment_size: usize, enable_gso: bool, enable_sendmmsg: bool, ) -> io::Result { if enable_gso { match send_to_gso(socket, buf, target, segment_size) { @@ -110,6 +187,17 @@ pub fn send_to( } } + if enable_sendmmsg { + match send_to_sendmmsg(socket, buf, target, segment_size) { + Ok(v) => { + return Ok(v); + }, + Err(e) => { + return Err(e); + }, + } + } + let mut off = 0; let mut left = buf.len(); let mut written = 0;