Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

apps: sendmmsg() support for quiche-server #993

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions tools/apps/src/bin/quiche-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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");
Expand Down
90 changes: 89 additions & 1 deletion tools/apps/src/sendto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<usize> {
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<usize> {
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<usize> {
if enable_gso {
match send_to_gso(socket, buf, target, segment_size) {
Expand All @@ -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;
Expand Down