Skip to content

slaac: add initial stateless address autoconfiguration (SLAAC) implementation #1039

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

bergzand
Copy link
Contributor

@bergzand bergzand commented Feb 5, 2025

This PR adds

  • Functions to derive ipv6 addresses from a Cidr and a LL address
  • An slaac implementation
  • Glue to hook it into the Interface

This works by having a separate module to track the slaac state machine. The Interface module passes the received router advertisements to this module and polls this to query whether router solicitations must be send and whether the addresses and routes on the interface need to be synced with the slaac state.

Compared to the dhcpv4, this module modifies the address and route state on the Interface within the module itself without any outside glue or socket required.

Currently there's no separate feature for slaac and it is pulled in when proto-ipv6 together with medium-ieee802154 or medium-ethernet is enabled. Done this way because I consider SLAAC to be an essential part of IPv6. However, I'm not opposed to adding a separate feature for slaac that depends on proto-ipv6

An example is provided that prints the addresses and routes on the interface every second for testing with router advertisement daemons such as radvd

Example output
Addresses:
  - fe80::1/64
Routes:

Addresses:
  - fe80::1/64
Routes:

Addresses:
  - fe80::1/64
  - 2001:db8::ff:fe00:1/64
Routes:
  - ::/0 via fe80::d83c:a5ff:fe9c:3a40

Addresses:
  - fe80::1/64
  - 2001:db8::ff:fe00:1/64
Routes:
  - ::/0 via fe80::d83c:a5ff:fe9c:3a40

Addresses:
  - fe80::1/64
  - 2001:db8::ff:fe00:1/64
Routes:
  - ::/0 via fe80::d83c:a5ff:fe9c:3a40

Addresses:
  - fe80::1/64
  - 2001:db8::ff:fe00:1/64
Routes:

Addresses:
  - fe80::1/64
  - 2001:db8::ff:fe00:1/64
Routes:

Alternative to #948

I can split out the initial commits of this PR into separate PRs if needed to ease reviewing.

This commit splits the state maintenance from the poll function to a
separate poll_maintenance function.
Copy link

codecov bot commented Feb 5, 2025

Codecov Report

Attention: Patch coverage is 95.41284% with 25 lines in your changes missing coverage. Please review.

Project coverage is 81.70%. Comparing base (3e3afb6) to head (8786ec8).
Report is 14 commits behind head on main.

Files with missing lines Patch % Lines
src/iface/interface/mod.rs 71.11% 13 Missing ⚠️
src/iface/slaac.rs 97.99% 6 Missing ⚠️
src/iface/interface/ipv6.rs 95.90% 5 Missing ⚠️
src/wire/ipv6.rs 98.18% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1039      +/-   ##
==========================================
+ Coverage   80.84%   81.70%   +0.85%     
==========================================
  Files          81       82       +1     
  Lines       28485    29501    +1016     
==========================================
+ Hits        23029    24103    +1074     
+ Misses       5456     5398      -58     

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

Copy link
Contributor

@Dominaezzz Dominaezzz left a comment

Choose a reason for hiding this comment

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

Looks good!

My main comment is here is "Why limit SLAAC to any specific mediums?"

@@ -23,4 +28,9 @@ pub use self::interface::{
};

pub use self::route::{Route, RouteTableFull, Routes};
#[cfg(all(
feature = "proto-ipv6",
any(feature = "medium-ethernet", feature = "medium-ieee802154")
Copy link
Contributor

Choose a reason for hiding this comment

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

SLAAC is a general IPv6 thing, why restrict it to any particular medium(s)?

Copy link
Member

Choose a reason for hiding this comment

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

SLAAC generates an IP addr based on the MAC addr. With IP medium there's no MAC addr. How is it supposed to work?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

as @Dirbaio mentioned, there needs to be support for each link layer with SLAAC, see for example rfc 2464 and rfc 4944.

Copy link
Contributor

@Dominaezzz Dominaezzz Mar 3, 2025

Choose a reason for hiding this comment

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

Sure for link-local address you want to use the MAC address (or equivalent) to generate it, but that's not quite the same for global or temporary addresses where you might want to hide your MAC address. I think in this case the user should be allowed to specify an interface identifier (which would be different from the MAC).

If Linux can do SLAAC for TUN devices, smoltcp can definitely do it for IP mediums.

EDIT: I'm looking at https://datatracker.ietf.org/doc/html/rfc4862#section-5.5

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure for link-local address you want to use the MAC address (or equivalent) to generate it, but that's not quite the same for global or temporary addresses where you might want to hide your MAC address. I think in this case the user should be allowed to specify an interface identifier (which would be different from the MAC).

I prefer to leave the additional logic required to switch the generation of interface identifiers to a follow up PR as this PR is already complex enough.

If Linux can do SLAAC for TUN devices, smoltcp can definitely do it for IP mediums.

If there's a way to add an interface identifier to a Medium::Ip Interface, it can be hooked in somehow. The whole process_ndisc where this code hooks into is skipped on Medium::Ip interfaces, so that would need to be modified. Not impossible, but also not sure if that must go in this PR.

Do you know if there's some special handling for SLAAC on Linux tun devices? Or does it always add a privacy address to that interface for slaac?

Copy link
Contributor

Choose a reason for hiding this comment

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

Or does it always add a privacy address to that interface for slaac?

Yes

I prefer to leave the additional logic required to switch the generation of interface identifiers to a follow up PR as this PR is already complex enough.

Sure the additional logic isn't necessary for this PR, I'm just saying the any(feature = "medium-ethernet", feature = "medium-ieee802154") isn't needed.

impl PrefixInformation {
/// Validates the prefix information option against check a, b, c in
/// https://www.rfc-editor.org/rfc/rfc4862#section-5.5.3
pub fn valid_prefix_info(&self) -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

This probably reads better?

Suggested change
pub fn valid_prefix_info(&self) -> bool {
pub fn is_valid_prefix_info(&self) -> bool {

@chrysn chrysn added this to Delta Mar 26, 2025
@chrysn chrysn moved this to Delta Suggestions in Delta Mar 26, 2025
@chrysn chrysn mentioned this pull request Mar 26, 2025
@kaspar030 kaspar030 moved this from Delta Suggestions to Todo Next in Delta Apr 8, 2025
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