Skip to content

udp: retry failed GSO sendmsg on EIO without GSO #2399

@mxinden

Description

@mxinden

We have multiple reports of Linux systems that might:

  1. Pass our GSO support check at runtime

    quinn/quinn-udp/src/unix.rs

    Lines 823 to 825 in 93b6d01

    /// Checks whether GSO support is available by checking the kernel version followed by setting
    /// the UDP_SEGMENT option on a socket
    pub(crate) fn max_gso_segments() -> usize {
  2. But then fail with EIO on the first GSO sendmsg

    quinn/quinn-udp/src/unix.rs

    Lines 345 to 349 in 93b6d01

    // Some network adapters and drivers do not support GSO. Unfortunately, Linux
    // offers no easy way for us to detect this short of an EIO or sometimes EINVAL
    // when we try to actually send datagrams using it.
    #[cfg(any(target_os = "linux", target_os = "android"))]
    if let Some(libc::EIO) | Some(libc::EINVAL) = e.raw_os_error() {

Reports:

Currently quinn-udp simply returns an error.

Instead, quinn-udp could attempt sending each segment individually.

Note that we already do a retry on other errors:

quinn/quinn-udp/src/unix.rs

Lines 362 to 376 in 93b6d01

// Some arguments to `sendmsg` are not supported. Switch to
// fallback mode and retry if we haven't already.
if e.raw_os_error() == Some(libc::EINVAL) && !state.sendmsg_einval() {
state.set_sendmsg_einval();
prepare_msg(
transmit,
&dst_addr,
&mut msg_hdr,
&mut iovec,
&mut cmsgs,
encode_src_ip,
state.sendmsg_einval(),
);
continue;
}

I am planning to land a hot-fix in Firefox for now, Relying on the QUIC layer to resend. relying on our QUIC state machine adds unnecessary delays.

Documenting this optimization here. I am not sure I will get to it any time soon.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions