Skip to content

Commit 6d36a43

Browse files
authored
change(api,dhcp): new proto types, migrations & dual-stack NetworkDef… (#2672)
<!-- Describe what this PR does --> Adds the additive proto, model, and schema surface needed for the IPv6 DHCP milestone without enabling DHCPv6 serving yet. This PR is intended to be additive and inert for DHCPv4 behavior. The new wire/config/schema fields are present for later milestones, but DHCPv6 request handling and Kea/DPU DHCPv6 serving are not enabled here. Closes #2381. ## Related issues <!-- Refer to existing GitHub issues here --> #2381 ## Type of Change <!-- Check one that best describes this PR --> - [ ] **Add** - New feature or capability - [ ] **Change** - Changes in existing functionality - [ ] **Fix** - Bug fixes - [ ] **Remove** - Removed features or deprecated functionality - [x] **Internal** - Internal changes (refactoring, tests, docs, etc.) ## Breaking Changes <!-- If checked, describe the breaking changes and migration steps --> <!-- Breaking changes are not generally permitted, please discuss on a GitHub discussion or with the development team if you believe you need to break a backward compatibility guarantee --> - [ ] **This PR contains breaking changes** ## Testing <!-- How was this tested? Check all that apply --> - [x] Unit tests added/updated - [x] Integration tests added/updated - [ ] Manual testing performed - [ ] No testing required (docs, internal refactor, etc.) ## Additional Notes <!-- Any additional context, deployment notes, or reviewer guidance -->
1 parent bd899c6 commit 6d36a43

37 files changed

Lines changed: 638 additions & 17 deletions

crates/agent/src/dhcp_server_grpc_client.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub mod proto {
2121

2222
use carbide_rpc_utils::dhcp::{
2323
DhcpConfig as ModelDhcpConfig, HostConfig as ModelHostConfig,
24-
InterfaceInfo as ModelInterfaceInfo,
24+
InterfaceInfo as ModelInterfaceInfo, InterfaceInfoV6 as ModelInterfaceInfoV6,
2525
};
2626
use carbide_uuid::machine::MachineInterfaceId;
2727
use proto::dhcp_server_control_client::DhcpServerControlClient;
@@ -47,6 +47,28 @@ impl From<ModelDhcpConfig> for proto::DhcpConfig {
4747
.collect(),
4848
carbide_provisioning_server_ipv4: c.carbide_provisioning_server_ipv4.to_string(),
4949
carbide_dhcp_server: c.carbide_dhcp_server.to_string(),
50+
carbide_nameservers_v6: c
51+
.carbide_nameservers_v6
52+
.iter()
53+
.map(|ip| ip.to_string())
54+
.collect(),
55+
carbide_ntpservers_v6: c
56+
.carbide_ntpservers_v6
57+
.iter()
58+
.map(|ip| ip.to_string())
59+
.collect(),
60+
carbide_dhcp_server_v6: c.carbide_dhcp_server_v6.map(|ip| ip.to_string()),
61+
dhcpv6_preferred_lifetime_secs: c.dhcpv6_preferred_lifetime_secs,
62+
dhcpv6_valid_lifetime_secs: c.dhcpv6_valid_lifetime_secs,
63+
}
64+
}
65+
}
66+
67+
impl From<ModelInterfaceInfoV6> for proto::InterfaceInfoV6 {
68+
fn from(i: ModelInterfaceInfoV6) -> Self {
69+
proto::InterfaceInfoV6 {
70+
address: i.address.map(|ip| ip.to_string()),
71+
prefix: i.prefix,
5072
}
5173
}
5274
}
@@ -60,6 +82,7 @@ impl From<ModelInterfaceInfo> for proto::InterfaceInfo {
6082
fqdn: i.fqdn,
6183
booturl: i.booturl,
6284
mtu: i.mtu,
85+
ipv6: i.ipv6.map(Into::into),
6386
}
6487
}
6588
}

crates/agent/src/ethernet_virtualization.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3463,6 +3463,7 @@ mod tests {
34633463
rebinding_time_secs: 432000,
34643464
carbide_api_url: None,
34653465
carbide_dhcp_server: Ipv4Addr::from([10, 217, 5, 39]),
3466+
..Default::default()
34663467
};
34673468

34683469
let mut network_config = rpc::ManagedHostNetworkConfigResponse {
@@ -3656,6 +3657,7 @@ mod tests {
36563657
rebinding_time_secs: 432000,
36573658
carbide_api_url: None,
36583659
carbide_dhcp_server: Ipv4Addr::from([10, 217, 5, 39]),
3660+
..Default::default()
36593661
};
36603662
let dhcp_contents = super::read_limited(g.path())?;
36613663
assert!(dhcp_contents.contains("vlan196"));

crates/api-core/src/cfg/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ applicable.
3434
| `listen_mode` | `ListenMode` | `Tls` | Transport mode: `plaintext_http1`, `plaintext_http2`, or `tls`. |
3535
| `auth` | `Option<AuthConfig>` || Authentication/authorization settings (see [AuthConfig](#authconfig)). |
3636
| `pools` | `Option<HashMap<String, ResourcePoolDef>>` || Resource pools that allocate IPs, VNIs, etc. Required but `Option` for partial-config merging. |
37-
| `networks` | `Option<HashMap<String, NetworkDefinition>>` || Networks created at startup. Alternative: `CreateNetworkSegment` gRPC. |
37+
| `networks` | `Option<HashMap<String, NetworkDefinition>>` || Networks created at startup. Alternative: `CreateNetworkSegment` gRPC. `NetworkDefinition` supports dual-stack seed-time segments with optional `prefix_v6` and `dhcpv6_link_address`; config edits do not retrofit prefixes onto an already-seeded segment because seed definitions are snapshotted on first create. |
3838
| `dpu_ipmi_tool_impl` | `Option<String>` || IPMI tool implementation for DPU power control (`"prod"` or `"fake"`). |
3939
| `dpu_ipmi_reboot_attempts` | `Option<u32>` || Retry count when IPMI errors during DPU reboot. |
4040
| `bmc_session_lockout_threshold` | `u32` | `3` | Consecutive BMC HTTP 401/403 responses before session-token login attempts stop for that BMC. |

crates/api-core/src/cfg/file.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3830,7 +3830,9 @@ firmware_url = "https://firmware.example.com/fw-b.bin"
38303830
&NetworkDefinition {
38313831
segment_type: NetworkDefinitionSegmentType::Admin,
38323832
prefix: "172.20.0.0/24".parse().unwrap(),
3833+
prefix_v6: None,
38333834
gateway: "172.20.0.1".parse().unwrap(),
3835+
dhcpv6_link_address: None,
38343836
mtu: 9000,
38353837
reserve_first: 5,
38363838
allocation_strategy: Default::default(),
@@ -3843,7 +3845,9 @@ firmware_url = "https://firmware.example.com/fw-b.bin"
38433845
&NetworkDefinition {
38443846
segment_type: NetworkDefinitionSegmentType::Underlay,
38453847
prefix: "172.99.0.0/26".parse().unwrap(),
3848+
prefix_v6: None,
38463849
gateway: "172.99.0.1".parse().unwrap(),
3850+
dhcpv6_link_address: None,
38473851
mtu: 1500,
38483852
reserve_first: 5,
38493853
allocation_strategy: Default::default(),
@@ -3856,7 +3860,9 @@ firmware_url = "https://firmware.example.com/fw-b.bin"
38563860
&NetworkDefinition {
38573861
segment_type: NetworkDefinitionSegmentType::HostInband,
38583862
prefix: "10.217.18.192/30".parse().unwrap(),
3863+
prefix_v6: None,
38593864
gateway: "10.217.18.193".parse().unwrap(),
3865+
dhcpv6_link_address: None,
38603866
mtu: 1500,
38613867
reserve_first: 1,
38623868
allocation_strategy: Default::default(),

crates/api-core/src/db_init.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ pub async fn ensure_static_assignments_segment(
227227
prefixes: vec![NewNetworkPrefix {
228228
prefix: "169.254.254.254/32".parse().unwrap(),
229229
gateway: None,
230+
dhcpv6_link_address: None,
230231
num_reserved: 1,
231232
}],
232233
vlan_id: None,

crates/api-core/src/dhcp/discover.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ async fn handle_overlay_from_dpa(
8282
fqdn: String::new(),
8383
prefix,
8484
ntp_servers: ntp_servers.iter().map(ToString::to_string).collect(),
85+
dhcpv6_preferred_lifetime_secs: None,
86+
dhcpv6_valid_lifetime_secs: None,
8587
})))
8688
}
8789

@@ -123,6 +125,8 @@ async fn handle_underlay_from_dpa(
123125
fqdn: String::new(),
124126
prefix,
125127
ntp_servers: ntp_servers.iter().map(ToString::to_string).collect(),
128+
dhcpv6_preferred_lifetime_secs: None,
129+
dhcpv6_valid_lifetime_secs: None,
126130
})))
127131
}
128132

crates/api-core/src/handlers/machine_interface_address.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ pub async fn find_interface_addresses(
218218
allocation_type: match a.allocation_type {
219219
AllocationType::Dhcp => "dhcp".to_string(),
220220
AllocationType::Static => "static".to_string(),
221+
AllocationType::Slaac => "slaac".to_string(),
221222
},
222223
})
223224
.collect();

crates/api-core/src/network_segment/allocate.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ impl PrefixAllocator {
182182
prefixes: vec![NewNetworkPrefix {
183183
prefix,
184184
gateway,
185+
dhcpv6_link_address: None,
185186
num_reserved: 0,
186187
}],
187188
vlan_id: None,
@@ -240,6 +241,7 @@ impl PrefixAllocator {
240241
&[NewNetworkPrefix {
241242
prefix,
242243
gateway,
244+
dhcpv6_link_address: None,
243245
num_reserved: 0,
244246
}],
245247
)

crates/api-core/src/setup.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,8 +1590,10 @@ mod tests {
15901590
NetworkDefinition {
15911591
segment_type,
15921592
prefix,
1593+
prefix_v6: None,
15931594
// Test helper placeholder; callers under test do not use this as a routable gateway.
15941595
gateway: prefix.network(),
1596+
dhcpv6_link_address: None,
15951597
mtu: 0,
15961598
reserve_first: 0,
15971599
allocation_strategy: Default::default(),

crates/api-core/src/tests/machine_discovery.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ async fn test_discover_dpu_by_source_ip(
197197
circuit_id: None,
198198
remote_id: None,
199199
desired_address: None,
200+
address_family: None,
201+
message_kind: None,
202+
duid: None,
200203
}))
201204
.await
202205
.unwrap()
@@ -237,6 +240,9 @@ async fn test_discover_dpu_not_create_machine(
237240
circuit_id: None,
238241
remote_id: None,
239242
desired_address: None,
243+
address_family: None,
244+
message_kind: None,
245+
duid: None,
240246
}))
241247
.await
242248
.unwrap()

0 commit comments

Comments
 (0)