mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-13 17:35:37 +00:00
feat: support allocating public IPv6 addresses from a provider (#2162)
* feat: support allocating public IPv6 addresses from a provider Add a provider/leaser architecture for public IPv6 address allocation between nodes in the same network: - A node with `--ipv6-public-addr-provider` advertises a delegable public IPv6 prefix (auto-detected from kernel routes or manually configured via `--ipv6-public-addr-prefix`). - Other nodes with `--ipv6-public-addr-auto` request a /128 lease from the selected provider via a new RPC service (PublicIpv6AddrRpc). - Leases have a 30s TTL, renewed every 10s by the client routine. - The provider allocates addresses deterministically from its prefix using instance-UUID-based hashing to prefer stable assignments. - Routes to peer leases are installed on the TUN device, and each client's own /128 is assigned as its IPv6 address. Also includes netlink IPv6 route table inspection, integration tests, and event-driven route/address reconciliation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -170,6 +170,15 @@ pub trait ConfigLoader: Send + Sync {
|
||||
fn get_ipv6(&self) -> Option<cidr::Ipv6Inet>;
|
||||
fn set_ipv6(&self, addr: Option<cidr::Ipv6Inet>);
|
||||
|
||||
fn get_ipv6_public_addr_provider(&self) -> bool;
|
||||
fn set_ipv6_public_addr_provider(&self, enabled: bool);
|
||||
|
||||
fn get_ipv6_public_addr_auto(&self) -> bool;
|
||||
fn set_ipv6_public_addr_auto(&self, enabled: bool);
|
||||
|
||||
fn get_ipv6_public_addr_prefix(&self) -> Option<cidr::Ipv6Cidr>;
|
||||
fn set_ipv6_public_addr_prefix(&self, prefix: Option<cidr::Ipv6Cidr>);
|
||||
|
||||
fn get_dhcp(&self) -> bool;
|
||||
fn set_dhcp(&self, dhcp: bool);
|
||||
|
||||
@@ -519,6 +528,9 @@ struct Config {
|
||||
instance_id: Option<uuid::Uuid>,
|
||||
ipv4: Option<String>,
|
||||
ipv6: Option<String>,
|
||||
ipv6_public_addr_provider: Option<bool>,
|
||||
ipv6_public_addr_auto: Option<bool>,
|
||||
ipv6_public_addr_prefix: Option<String>,
|
||||
dhcp: Option<bool>,
|
||||
network_identity: Option<NetworkIdentity>,
|
||||
listeners: Option<Vec<url::Url>>,
|
||||
@@ -700,6 +712,43 @@ impl ConfigLoader for TomlConfigLoader {
|
||||
self.config.lock().unwrap().ipv6 = addr.map(|addr| addr.to_string());
|
||||
}
|
||||
|
||||
fn get_ipv6_public_addr_provider(&self) -> bool {
|
||||
self.config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.ipv6_public_addr_provider
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn set_ipv6_public_addr_provider(&self, enabled: bool) {
|
||||
self.config.lock().unwrap().ipv6_public_addr_provider = Some(enabled);
|
||||
}
|
||||
|
||||
fn get_ipv6_public_addr_auto(&self) -> bool {
|
||||
self.config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.ipv6_public_addr_auto
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn set_ipv6_public_addr_auto(&self, enabled: bool) {
|
||||
self.config.lock().unwrap().ipv6_public_addr_auto = Some(enabled);
|
||||
}
|
||||
|
||||
fn get_ipv6_public_addr_prefix(&self) -> Option<cidr::Ipv6Cidr> {
|
||||
let locked_config = self.config.lock().unwrap();
|
||||
locked_config
|
||||
.ipv6_public_addr_prefix
|
||||
.as_ref()
|
||||
.and_then(|s| s.parse().ok())
|
||||
}
|
||||
|
||||
fn set_ipv6_public_addr_prefix(&self, prefix: Option<cidr::Ipv6Cidr>) {
|
||||
self.config.lock().unwrap().ipv6_public_addr_prefix =
|
||||
prefix.map(|prefix| prefix.to_string());
|
||||
}
|
||||
|
||||
fn get_dhcp(&self) -> bool {
|
||||
self.config.lock().unwrap().dhcp.unwrap_or_default()
|
||||
}
|
||||
@@ -1312,6 +1361,26 @@ source = "user"
|
||||
assert!(!explicit_user.dump().contains("[source]"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ipv6_public_addr_config_roundtrip() {
|
||||
let config = TomlConfigLoader::default();
|
||||
let prefix: cidr::Ipv6Cidr = "2001:db8:100::/64".parse().unwrap();
|
||||
|
||||
config.set_ipv6_public_addr_provider(true);
|
||||
config.set_ipv6_public_addr_auto(true);
|
||||
config.set_ipv6_public_addr_prefix(Some(prefix));
|
||||
|
||||
assert!(config.get_ipv6_public_addr_provider());
|
||||
assert!(config.get_ipv6_public_addr_auto());
|
||||
assert_eq!(config.get_ipv6_public_addr_prefix(), Some(prefix));
|
||||
|
||||
let dumped = config.dump();
|
||||
let loaded = TomlConfigLoader::new_from_str(&dumped).unwrap();
|
||||
assert!(loaded.get_ipv6_public_addr_provider());
|
||||
assert!(loaded.get_ipv6_public_addr_auto());
|
||||
assert_eq!(loaded.get_ipv6_public_addr_prefix(), Some(prefix));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn full_example_test() {
|
||||
let config_str = r#"
|
||||
|
||||
Reference in New Issue
Block a user