Skip to content

Commit 9dea821

Browse files
committed
feat(dhcp): include the host's IPv6 DNS resolvers in the agent's DHCP config
The agent reads a host's nameservers from the DPU's dual-stack `ServiceAddresses`, then builds the `DhcpConfig` it sends to `forge-dhcp-server`. It now splits those nameservers by family at both build sites -- the gRPC control path (`update_dhcp_via_grpc`) and the on-disk config path (`write_dhcp_v4_server_config`) -- and fills `carbide_nameservers_v6` with the IPv6 set, threaded through `from_forge_dhcp_config` and `build_server_config`. The agent used to filter these nameservers to IPv4 and drop the IPv6 ones, with a TODO marking exactly this gap. The IPv4 path is unchanged -- it still drives the DHCPv4 option-6 nameservers -- and the IPv6 set stays inert until a delivery channel consumes it (RA RDNSS or DHCPv6, see #2644 / #1263). Tests extend the file-path builder test to assert an IPv6 nameserver round-trips through the written config, alongside the builder's own dual-stack case. This supports #2640. Signed-off-by: Chet Nichols III <chetn@nvidia.com>
1 parent 7e9c6c9 commit 9dea821

3 files changed

Lines changed: 45 additions & 12 deletions

File tree

crates/agent/src/dhcp.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17-
use std::net::Ipv4Addr;
17+
use std::net::{Ipv4Addr, Ipv6Addr};
1818

1919
use ::rpc::forge as rpc;
2020
use carbide_rpc_utils::dhcp::HostConfig;
@@ -64,12 +64,14 @@ pub fn build_server_config(
6464
pxe_ip: Ipv4Addr,
6565
ntpservers: Vec<Ipv4Addr>,
6666
nameservers: Vec<Ipv4Addr>,
67+
nameservers_v6: Vec<Ipv6Addr>,
6768
loopback_ip: Ipv4Addr,
6869
) -> Result<String, eyre::Report> {
6970
let dhcp_config = carbide_rpc_utils::dhcp::DhcpConfig::from_forge_dhcp_config(
7071
pxe_ip,
7172
ntpservers,
7273
nameservers,
74+
nameservers_v6,
7375
loopback_ip,
7476
)?;
7577

crates/agent/src/ethernet_virtualization.rs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use std::collections::HashMap;
1919
use std::ffi::CStr;
2020
use std::fs::File;
2121
use std::io::Read;
22-
use std::net::{IpAddr, Ipv4Addr};
22+
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2323
use std::path::{Path, PathBuf};
2424
use std::str::FromStr;
2525
use std::time::Duration;
@@ -1075,6 +1075,15 @@ async fn update_dhcp_via_grpc(
10751075
})
10761076
.collect::<Vec<Ipv4Addr>>();
10771077

1078+
let nameservers_v6 = service_addrs
1079+
.nameservers
1080+
.iter()
1081+
.filter_map(|x| match x {
1082+
IpAddr::V6(x) => Some(*x),
1083+
_ => None,
1084+
})
1085+
.collect::<Vec<Ipv6Addr>>();
1086+
10781087
let ntpservers_v4 = build_dhcp_ntp_servers(network_config, service_addrs);
10791088

10801089
let pxe_ip_v4 = service_addrs
@@ -1095,6 +1104,7 @@ async fn update_dhcp_via_grpc(
10951104
pxe_ip_v4,
10961105
ntpservers_v4,
10971106
nameservers_v4,
1107+
nameservers_v6,
10981108
loopback_ip,
10991109
)?;
11001110
let mut host_config = carbide_rpc_utils::dhcp::HostConfig::try_from(
@@ -1471,10 +1481,9 @@ fn write_dhcp_v4_server_config(
14711481

14721482
let loopback_ip = mh_nc.loopback_ip.parse()?;
14731483

1474-
// Filter to IPv4, since this is specifically for the DHCPv4 server
1475-
// config, and the input ServiceAddresses holds both families.
1476-
// Again, we'll eventually have a specific builder for a DHCPv6
1477-
// that does similar things with ServiceAddresses, but for IPv6.
1484+
// Split the dual-stack nameservers by family: the IPv4 set drives the
1485+
// DHCPv4 options written here, while the IPv6 set is held in the config for
1486+
// the eventual DHCPv6 / RA consumer (inert in the DHCPv4 path for now).
14781487
let nameservers_v4 = service_addrs
14791488
.nameservers
14801489
.iter()
@@ -1484,6 +1493,15 @@ fn write_dhcp_v4_server_config(
14841493
})
14851494
.collect::<Vec<Ipv4Addr>>();
14861495

1496+
let nameservers_v6 = service_addrs
1497+
.nameservers
1498+
.iter()
1499+
.filter_map(|x| match x {
1500+
IpAddr::V6(x) => Some(*x),
1501+
_ => None,
1502+
})
1503+
.collect::<Vec<Ipv6Addr>>();
1504+
14871505
let ntpservers_v4 = build_dhcp_ntp_servers(nc, service_addrs);
14881506

14891507
let pxe_ip_v4 = service_addrs
@@ -1517,8 +1535,13 @@ fn write_dhcp_v4_server_config(
15171535
Err(err) => tracing::error!("Write DHCP server {}: {err:#}", dhcp_server_path.server),
15181536
}
15191537

1520-
let next_contents =
1521-
dhcp::build_server_config(pxe_ip_v4, ntpservers_v4, nameservers_v4, loopback_ip)?;
1538+
let next_contents = dhcp::build_server_config(
1539+
pxe_ip_v4,
1540+
ntpservers_v4,
1541+
nameservers_v4,
1542+
nameservers_v6,
1543+
loopback_ip,
1544+
)?;
15221545
match write(
15231546
next_contents,
15241547
&dhcp_server_path.config,
@@ -3467,7 +3490,7 @@ mod tests {
34673490
rebinding_time_secs: 432000,
34683491
carbide_api_url: None,
34693492
carbide_dhcp_server: Ipv4Addr::from([10, 217, 5, 39]),
3470-
carbide_nameservers_v6: vec![],
3493+
carbide_nameservers_v6: vec!["2001:db8::53".parse().unwrap()],
34713494
};
34723495

34733496
let mut network_config = rpc::ManagedHostNetworkConfigResponse {
@@ -3565,7 +3588,7 @@ mod tests {
35653588
IpAddr::from([127, 0, 0, 2]),
35663589
IpAddr::from([127, 0, 0, 3]),
35673590
],
3568-
nameservers: vec![IpAddr::from([10, 1, 1, 1])],
3591+
nameservers: vec![IpAddr::from([10, 1, 1, 1]), "2001:db8::53".parse().unwrap()],
35693592
};
35703593

35713594
let mut host_config_str =

crates/rpc-utils/src/dhcp.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,12 @@ impl DhcpConfig {
8888
carbide_provisioning_server_ipv4: Ipv4Addr,
8989
carbide_ntpservers: Vec<Ipv4Addr>,
9090
carbide_nameservers: Vec<Ipv4Addr>,
91+
carbide_nameservers_v6: Vec<Ipv6Addr>,
9192
loopback_ip: Ipv4Addr,
9293
) -> Result<Self, DhcpDataError> {
9394
Ok(DhcpConfig {
9495
carbide_nameservers,
96+
carbide_nameservers_v6,
9597
carbide_ntpservers,
9698
carbide_provisioning_server_ipv4,
9799
carbide_dhcp_server: loopback_ip,
@@ -303,7 +305,7 @@ impl IntoIterator for DhcpTimestamps {
303305

304306
#[cfg(test)]
305307
mod tests {
306-
use std::net::Ipv4Addr;
308+
use std::net::{Ipv4Addr, Ipv6Addr};
307309

308310
use carbide_test_support::Outcome::*;
309311
use carbide_test_support::{scenarios, value_scenarios};
@@ -323,6 +325,7 @@ mod tests {
323325
dhcp_server: Ipv4Addr,
324326
ntpservers: Vec<Ipv4Addr>,
325327
nameservers: Vec<Ipv4Addr>,
328+
nameservers_v6: Vec<Ipv6Addr>,
326329
lease_time_secs: u32,
327330
}
328331

@@ -413,24 +416,27 @@ mod tests {
413416
}
414417

415418
fn summarize_dhcp_config(
416-
(provisioning_server, ntpservers, nameservers, dhcp_server): (
419+
(provisioning_server, ntpservers, nameservers, nameservers_v6, dhcp_server): (
417420
Ipv4Addr,
418421
Vec<Ipv4Addr>,
419422
Vec<Ipv4Addr>,
423+
Vec<Ipv6Addr>,
420424
Ipv4Addr,
421425
),
422426
) -> Result<DhcpConfigSummary, &'static str> {
423427
DhcpConfig::from_forge_dhcp_config(
424428
provisioning_server,
425429
ntpservers,
426430
nameservers,
431+
nameservers_v6,
427432
dhcp_server,
428433
)
429434
.map(|config| DhcpConfigSummary {
430435
provisioning_server: config.carbide_provisioning_server_ipv4,
431436
dhcp_server: config.carbide_dhcp_server,
432437
ntpservers: config.carbide_ntpservers,
433438
nameservers: config.carbide_nameservers,
439+
nameservers_v6: config.carbide_nameservers_v6,
434440
lease_time_secs: config.lease_time_secs,
435441
})
436442
.map_err(dhcp_error_kind)
@@ -463,12 +469,14 @@ mod tests {
463469
Ipv4Addr::new(192, 0, 2, 10),
464470
vec![Ipv4Addr::new(192, 0, 2, 20)],
465471
vec![Ipv4Addr::new(192, 0, 2, 53)],
472+
vec!["2001:db8::53".parse::<Ipv6Addr>().unwrap()],
466473
Ipv4Addr::new(127, 0, 0, 2),
467474
) => Yields(DhcpConfigSummary {
468475
provisioning_server: Ipv4Addr::new(192, 0, 2, 10),
469476
dhcp_server: Ipv4Addr::new(127, 0, 0, 2),
470477
ntpservers: vec![Ipv4Addr::new(192, 0, 2, 20)],
471478
nameservers: vec![Ipv4Addr::new(192, 0, 2, 53)],
479+
nameservers_v6: vec!["2001:db8::53".parse::<Ipv6Addr>().unwrap()],
472480
lease_time_secs: DEFAULT_LEASE_TIME_SECS,
473481
}),
474482
}

0 commit comments

Comments
 (0)