summaryrefslogtreecommitdiff
path: root/test/sys/test_socket.rs
diff options
context:
space:
mode:
authorGleb Pomykalov <gleb@lancastr.com>2020-04-07 23:40:14 +0300
committerGleb Pomykalov <gleb@lancastr.com>2020-04-25 23:45:50 +0300
commitb1b64ee4a79b2d5e81362a48ad3b9418f0057a09 (patch)
treed648a93c0edb53ee0f236823dab5eb8cb3528b26 /test/sys/test_socket.rs
parent9c497e02c16e1a4630db295577c0363935d2a178 (diff)
downloadnix-b1b64ee4a79b2d5e81362a48ad3b9418f0057a09.zip
Support UDP GSO and GRO on linux
Diffstat (limited to 'test/sys/test_socket.rs')
-rw-r--r--test/sys/test_socket.rs88
1 files changed, 83 insertions, 5 deletions
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index bd5c373b..9194f4c5 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -169,8 +169,10 @@ mod recvfrom {
const MSG: &'static [u8] = b"Hello, World!";
- fn sendrecv<F>(rsock: RawFd, ssock: RawFd, f: F) -> Option<SockAddr>
- where F: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static
+ fn sendrecv<Fs, Fr>(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option<SockAddr>
+ where
+ Fs: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static,
+ Fr: FnMut(usize, Option<SockAddr>),
{
let mut buf: [u8; 13] = [0u8; 13];
let mut l = 0;
@@ -179,12 +181,13 @@ mod recvfrom {
let send_thread = thread::spawn(move || {
let mut l = 0;
while l < std::mem::size_of_val(MSG) {
- l += f(ssock, &MSG[l..], MsgFlags::empty()).unwrap();
+ l += f_send(ssock, &MSG[l..], MsgFlags::empty()).unwrap();
}
});
while l < std::mem::size_of_val(MSG) {
let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap();
+ f_recv(len, from_);
from = from_;
l += len;
}
@@ -200,7 +203,7 @@ mod recvfrom {
// Ignore from for stream sockets
let _ = sendrecv(fd1, fd2, |s, m, flags| {
send(s, m, flags)
- });
+ }, |_, _| {});
}
#[test]
@@ -222,10 +225,85 @@ mod recvfrom {
).expect("send socket failed");
let from = sendrecv(rsock, ssock, move |s, m, flags| {
sendto(s, m, &sock_addr, flags)
- });
+ },|_, _| {});
// UDP sockets should set the from address
assert_eq!(AddressFamily::Inet, from.unwrap().family());
}
+
+ #[cfg(target_os = "linux")]
+ mod udp_offload {
+ use super::*;
+ use nix::sys::uio::IoVec;
+ use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment};
+
+ #[test]
+ pub fn gso() {
+ require_kernel_version!(udp_offload::gso, ">= 4.18");
+
+ // In this test, we send the data and provide a GSO segment size.
+ // Since we are sending the buffer of size 13, six UDP packets
+ // with size 2 and two UDP packet with size 1 will be sent.
+ let segment_size: u16 = 2;
+
+ let std_sa = SocketAddr::from_str("127.0.0.1:6791").unwrap();
+ let inet_addr = InetAddr::from_std(&std_sa);
+ let sock_addr = SockAddr::new_inet(inet_addr);
+ let rsock = socket(AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None
+ ).unwrap();
+
+ setsockopt(rsock, UdpGsoSegment, &(segment_size as _))
+ .expect("setsockopt UDP_SEGMENT failed");
+
+ bind(rsock, &sock_addr).unwrap();
+ let ssock = socket(
+ AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None,
+ ).expect("send socket failed");
+
+ let mut num_packets_received: i32 = 0;
+
+ sendrecv(rsock, ssock, move |s, m, flags| {
+ let iov = [IoVec::from_slice(m)];
+ let cmsg = ControlMessage::UdpGsoSegments(&segment_size);
+ sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr))
+ }, {
+ let num_packets_received_ref = &mut num_packets_received;
+
+ move |len, _| {
+ // check that we receive UDP packets with payload size
+ // less or equal to segment size
+ assert!(len <= segment_size as usize);
+ *num_packets_received_ref += 1;
+ }
+ });
+
+ // Buffer size is 13, we will receive six packets of size 2,
+ // and one packet of size 1.
+ assert_eq!(7, num_packets_received);
+ }
+
+ #[test]
+ pub fn gro() {
+ require_kernel_version!(udp_offload::gro, ">= 5.3");
+
+ // It's hard to guarantee receiving GRO packets. Just checking
+ // that `setsockopt` doesn't fail with error
+
+ let rsock = socket(AddressFamily::Inet,
+ SockType::Datagram,
+ SockFlag::empty(),
+ None
+ ).unwrap();
+
+ setsockopt(rsock, UdpGroSegment, &true)
+ .expect("setsockopt UDP_GRO failed");
+ }
+ }
}
// Test error handling of our recvmsg wrapper