Skip to content

Conversation

@maxslarsson
Copy link

Improve IPv4 source address selection for multi-subnet interfaces

Problem

When an interface has multiple IPv4 addresses in different subnets, the current implementation always returns the first IPv4 address as the source address, regardless of the destination. This causes issues in multi-homed configurations where the interface serves multiple networks.

I encountered this issue with a setup where I registered an interface like this:

let first_ip = Ipv4Cidr::new(Ipv4Addr::new(172, 18, 1, 2), 24);
let second_ip = Ipv4Cidr::new(Ipv4Addr::new(172, 24, 24, 14), 24);

let mut interface = Interface::new(interface_config, &mut device, now);
interface.update_ip_addrs(|a| {
    a.push(first_ip.into()).unwrap();
    a.push(second_ip.into()).unwrap();
});

When a smoltcp socket attempts to send a packet to a device on the 172.24.24.0/24 network, the initial ARP packets that were sent were being sent with the wrong source IP (172.18.1.2 instead of 172.24.24.14). This caused the remote device to ignore the ARP requests since they appeared to come from a different network, causing the packet to never be sent.

Solution

This PR enhances the IPv4 source address selection algorithm to be subnet-aware. The new implementation:

  1. First attempts to find an interface address that is in the same subnet as the destination address
  2. Falls back to the first IPv4 address if no matching subnet is found (preserving backward compatibility)

Changes

  • Modified get_source_address_ipv4() in src/iface/interface/ipv4.rs to iterate through all interface addresses and check if they're in the same subnet as the destination
  • Updated documentation to reflect the new subnet-aware behavior
  • The change maintains backward compatibility - if no subnet match is found, it returns the first IPv4 address as before

Now when communicating with a device at 172.24.24.100, the source address will correctly be 172.24.24.14 instead of 172.18.1.2.

@codecov
Copy link

codecov bot commented Jul 15, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.63%. Comparing base (a54589c) to head (4f739af).
⚠️ Report is 28 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1074   +/-   ##
=======================================
  Coverage   79.62%   79.63%           
=======================================
  Files          81       81           
  Lines       24218    24224    +6     
=======================================
+ Hits        19284    19291    +7     
+ Misses       4934     4933    -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Dirbaio
Copy link
Member

Dirbaio commented Jul 15, 2025

Looks good!

  • Can you do the same change for IPv6?
  • Can you add tests?

@maxslarsson
Copy link
Author

  • Just looked into it and it seems that it is automatically handled for IPv6 by rule 8 in RFC 6724: use longest matching prefix. I added a test case for it to verify that that is the case.
  • I added test cases for both IPv4 and IPv6, following the existing standards and style.

Please let me know if there's anything else!

@thvdveld
Copy link
Contributor

thvdveld commented Oct 2, 2025

Looks good to me, thank you!

@thvdveld thvdveld added this pull request to the merge queue Oct 2, 2025
Merged via the queue into smoltcp-rs:main with commit 8314870 Oct 2, 2025
13 checks passed
@maxslarsson maxslarsson deleted the set-ipv4-src-addr branch October 5, 2025 22:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants