Skip to content

Conversation

@RaghavendraRQ
Copy link

On Linux, enables IP_RECVERR and IPV6_RECVERR socket options

This allows the socket to receive ICMP errors via the error queue, enabling faster detection of network unreachability instead of waiting for connection timeouts.

Features Implemented

  • Enable IP_RECVERR and IPV6_RECVERR socket options on Linux
  • Add error queue polling in recv path
  • Add IcmpError type for ICMP error reporting
  • Add tests for ICMP error handling (Not Completed)

Closes #2052

@RaghavendraRQ RaghavendraRQ force-pushed the linux-ip-recverr branch 4 times, most recently from 5338a62 to aa6bf63 Compare October 21, 2025 11:26
Copy link
Collaborator

@mxinden mxinden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work. I will take a more in-depth look.

Copy link
Contributor

@thomaseizinger thomaseizinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gave this a first pass.

if is_ip_err || is_ipv6_err {
let err_data = unsafe { cmsg::decode::<SockExtendedErr, libc::cmsghdr>(cmsg) };

let addr = unsafe {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not have this code somewhere already in the codebase? Perhaps extracting a small utility function could make this a bit more concise.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered factoring it out, but this logic is fairly localized and only used here. so I’ll keep it inline for clarity.

@RaghavendraRQ RaghavendraRQ force-pushed the linux-ip-recverr branch 2 times, most recently from 032a179 to a9e7e2a Compare October 25, 2025 13:07
@RaghavendraRQ
Copy link
Author

This is my first open-source contribution, so I understand there may be several mistakes. Thank you for taking the time to review my work and provide guidance—I really appreciate it.

Copy link
Contributor

@thomaseizinger thomaseizinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great progress. One big item to discuss.

recv_err(socket.0)
}

#[cfg(not(target_os = "linux"))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should aim for a unified API across all platforms, even if they currently don't return a value. Otherwise code that uses this also needs to use a cfg to compile on multiple platforms.


let mut control = cmsg::Aligned([0u8; CMSG_LEN]);

// We don't need actual data, just the error info
Copy link
Contributor

@thomaseizinger thomaseizinger Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! I understand now. So to receive error info, we pass a flag to recvmsg but otherwise it is the same syscall. An alternative design would be to do this as part of the other recv flow and store the received ICMP messages in a (bounded) queue. That would be more efficient in terms of syscall usage, especially because most of the time, this syscall here is not going to return anything. Yet, an application wanting to handle this still needs to call this in a loop with the other recv, taking up CPU usage of the recv hot path.

Curious to hear what other people think about this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your suggestion makes sense to me.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. In case someone here knows, what is the intended use, or asked differently, how do other applications use it?

Comment on lines 245 to 252
struct SockExtendedErr {
ee_errno: u32,
ee_origin: u8,
ee_type: u8,
ee_code: u8,
ee_pad: u8,
ee_info: u32,
ee_data: u32,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: without any compelling reason to the contrary (like shared standardization with other APIs), suggest naming this SocketExtendedError and dropping the common ee_ prefix on fields (which is a kind of stuttering).

Also, since these only seem relevant on Unix, suggest that these should live in the unix module?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, since these only seem relevant on Unix, suggest that these should live in the unix module?

I don't think you addressed this.

Also, please keep it these types near the bottom of the module to maintain the top-down ordering of items.

HostUnreachable,
PortUnreachable,
PacketTooBig,
Other { icmp_type: u8, icmp_code: u8 },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: drop the icmp_ prefix, which is pretty obvious for a type named IcmpErrorKind.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since type is a reserved keyword in Rust, it can’t be used directly as a field name, We can use raw identifier instead r#type. Can i do that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems okay to me.


#[cfg(target_os = "linux")]
impl IcmpErrorKind {
fn from_extended_err(err: &SockExtendedErr) -> Self {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like this should be SocketExtendedError::kind().

Can we name the magic constants for type and code here with their common libc or whatever names?

@djc
Copy link
Member

djc commented Oct 28, 2025

Please squash all your changes before pushing.

chore(ip_recverr): Testing with socket setup similar to cmsg in recv

feat(ip_recverr): Initialised socket options for IPV4 and V6

feat(ip_recverr): Add error read queue function

chore(ip_recverr): Add error handling after recieving normal packets

test(ip_recverr): Start the test cases for IP_RECVERR

test(ip_recverr): Complete the test cases for ip_recverr and ipv6

test(ip_recverr): handle expected send failure instead of panicking

style: Format the files using rustfmt

style(recv_err): Change the name of the unused function

refactor(ip_recverr): change the ICMPErr to enum kind

refactor(ip_recverr): COnversion from SockExtendedErr to ICMPErrKind

refactor(ip_recverr): Remove ICMPErr from recv and add seperate recv_icmp_err

test(ip_recverr): Change the test files following new method

Apply suggestions from code review

Co-authored-by: Thomas Eizinger <[email protected]>

refactor: address code review feedback
- Use early returns to reduce nesting
- Replace match with unwrap in tests
- Add non-Linux fallback implementation

fix(ip_recverr): Continue to next control message instead of return

test(ip_recverr): Fix the socket binding error from OS, now sends proper network error

fix(ip_recverr): rename IcmpError for non linux platforms

fix(pacing): allow ±0ns tolerance in computes_pause_correctly test on i386
-Used Duration::abs_diff() instead of manual difference for cleaner and more robust duration comparison.
-added inline formatting as required.

build(deps): bump rustls-platform-verifier from 0.6.1 to 0.6.2

Bumps [rustls-platform-verifier](https://github.com/rustls/rustls-platform-verifier) from 0.6.1 to 0.6.2.
- [Release notes](https://github.com/rustls/rustls-platform-verifier/releases)
- [Changelog](https://github.com/rustls/rustls-platform-verifier/blob/main/CHANGELOG)
- [Commits](rustls/rustls-platform-verifier@v/0.6.1...v/0.6.2)

---
updated-dependencies:
- dependency-name: rustls-platform-verifier
  dependency-version: 0.6.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>

refactor(ip_recverr): Change SockExtendedError as suggested

fix(ip_recverr): Add IcmpError for non linux platforms

refactor(ip_recverr): Change to SockExtendedError Kind
@djc
Copy link
Member

djc commented Oct 29, 2025

Please squash all your changes before pushing.

Including merges.

@RaghavendraRQ RaghavendraRQ force-pushed the linux-ip-recverr branch 2 times, most recently from 5252988 to 7278847 Compare November 3, 2025 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for IP_RECVERR and IPV6_RECVERR

4 participants