summaryrefslogtreecommitdiff
path: root/src/sys/socket
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 /src/sys/socket
parent9c497e02c16e1a4630db295577c0363935d2a178 (diff)
downloadnix-b1b64ee4a79b2d5e81362a48ad3b9418f0057a09.zip
Support UDP GSO and GRO on linux
Diffstat (limited to 'src/sys/socket')
-rw-r--r--src/sys/socket/mod.rs43
-rw-r--r--src/sys/socket/sockopt.rs5
2 files changed, 46 insertions, 2 deletions
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index 6b2d1ad0..18673e16 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -463,6 +463,18 @@ pub enum ControlMessageOwned {
target_os = "openbsd",
))]
Ipv4RecvDstAddr(libc::in_addr),
+
+ /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP
+ /// packets from a single sender.
+ /// Fixed-size payloads are following one by one in a receive buffer.
+ /// This Control Message indicates the size of all smaller packets,
+ /// except, maybe, the last one.
+ ///
+ /// `UdpGroSegment` socket option should be enabled on a socket
+ /// to allow receiving GRO packets.
+ #[cfg(target_os = "linux")]
+ UdpGroSegments(u16),
+
/// Catch-all variant for unimplemented cmsg types.
#[doc(hidden)]
Unknown(UnknownCmsg),
@@ -546,6 +558,11 @@ impl ControlMessageOwned {
let dl = ptr::read_unaligned(p as *const libc::in_addr);
ControlMessageOwned::Ipv4RecvDstAddr(dl)
},
+ #[cfg(target_os = "linux")]
+ (libc::SOL_UDP, libc::UDP_GRO) => {
+ let gso_size: u16 = ptr::read_unaligned(p as *const _);
+ ControlMessageOwned::UdpGroSegments(gso_size)
+ },
(_, _) => {
let sl = slice::from_raw_parts(p, len);
let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(&sl[..]));
@@ -617,6 +634,16 @@ pub enum ControlMessage<'a> {
))]
AlgSetAeadAssoclen(&'a u32),
+ /// UDP GSO makes it possible for applications to generate network packets
+ /// for a virtual MTU much greater than the real one.
+ /// The length of the send data no longer matches the expected length on
+ /// the wire.
+ /// The size of the datagram payload as it should appear on the wire may be
+ /// passed through this control message.
+ /// Send buffer should consist of multiple fixed-size wire payloads
+ /// following one by one, and the last, possibly smaller one.
+ #[cfg(target_os = "linux")]
+ UdpGsoSegments(&'a u16),
}
// An opaque structure used to prevent cmsghdr from being a public type
@@ -687,6 +714,10 @@ impl<'a> ControlMessage<'a> {
ControlMessage::AlgSetAeadAssoclen(len) => {
len as *const _ as *const u8
},
+ #[cfg(target_os = "linux")]
+ ControlMessage::UdpGsoSegments(gso_size) => {
+ gso_size as *const _ as *const u8
+ },
};
unsafe {
ptr::copy_nonoverlapping(
@@ -719,6 +750,10 @@ impl<'a> ControlMessage<'a> {
ControlMessage::AlgSetAeadAssoclen(len) => {
mem::size_of_val(len)
},
+ #[cfg(target_os = "linux")]
+ ControlMessage::UdpGsoSegments(gso_size) => {
+ mem::size_of_val(gso_size)
+ },
}
}
@@ -730,7 +765,9 @@ impl<'a> ControlMessage<'a> {
ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
#[cfg(any(target_os = "android", target_os = "linux"))]
ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) |
- ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG ,
+ ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG,
+ #[cfg(target_os = "linux")]
+ ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP,
}
}
@@ -752,6 +789,10 @@ impl<'a> ControlMessage<'a> {
ControlMessage::AlgSetAeadAssoclen(_) => {
libc::ALG_SET_AEAD_ASSOCLEN
},
+ #[cfg(target_os = "linux")]
+ ControlMessage::UdpGsoSegments(_) => {
+ libc::UDP_SEGMENT
+ },
}
}
diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs
index 6b8180b3..d0ef4b65 100644
--- a/src/sys/socket/sockopt.rs
+++ b/src/sys/socket/sockopt.rs
@@ -308,7 +308,10 @@ sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
target_os = "openbsd",
))]
sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
-
+#[cfg(target_os = "linux")]
+sockopt_impl!(Both, UdpGsoSegment, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int);
+#[cfg(target_os = "linux")]
+sockopt_impl!(Both, UdpGroSegment, libc::IPPROTO_UDP, libc::UDP_GRO, bool);
#[cfg(any(target_os = "android", target_os = "linux"))]
#[derive(Copy, Clone, Debug)]