Skip to content

Commit 6479763

Browse files
[sled-hardware-types] Move I/O logic out of types crate (#10028)
sled-hardware-types depended on illumos-utils and omicron-common because `BootstrapInterface::ip()` performed I/O via `Dladm::get_mac()`. We don't really want those dependencies here, particularly for downstream crates that only need the type definitions (e.g. ddm-admin-client, wicketd). Extract `BoostrapInterface::ip()` as a free function `bootstrap_ip()` in sled-hardware::underlay, which already depends on illumos-utils and omicron-common. `BootstrapInterface`, `BOOTSTRAP_PREFIX` and `BOOTSTRAP_MASK` remain in sled-hardware-types.
1 parent 544d375 commit 6479763

6 files changed

Lines changed: 76 additions & 68 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

installinator/src/bootstrap.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use omicron_common::backoff::retry_notify;
1919
use omicron_common::backoff::retry_policy_internal_service_aggressive;
2020
use omicron_ddm_admin_client::Client as DdmAdminClient;
2121
use sled_hardware::underlay;
22-
use sled_hardware_types::underlay::BootstrapInterface;
22+
use sled_hardware::underlay::BootstrapInterface;
2323
use slog::Logger;
2424
use slog::info;
2525
use slog_error_chain::InlineErrorChain;
@@ -70,9 +70,11 @@ pub(crate) async fn bootstrap_sled(
7070
.context("failed to ensure bootstrap etherstub vnic existence")?;
7171

7272
// Use the mac address of the first link to derive our bootstrap address.
73-
let ip = BootstrapInterface::GlobalZone.ip(&links[0]).await.with_context(
74-
|| format!("failed to derive a bootstrap prefix from {:?}", links[0]),
75-
)?;
73+
let ip = underlay::bootstrap_ip(BootstrapInterface::GlobalZone, &links[0])
74+
.await
75+
.with_context(|| {
76+
format!("failed to derive a bootstrap prefix from {:?}", links[0])
77+
})?;
7678

7779
Zones::ensure_has_global_zone_v6_address(
7880
bootstrap_etherstub_vnic,

sled-agent/src/bootstrap/pre_server.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use sled_agent_config_reconciler::ConfigReconcilerSpawnToken;
3939
use sled_hardware::DendriteAsic;
4040
use sled_hardware::SledMode;
4141
use sled_hardware::underlay;
42-
use sled_hardware_types::underlay::BootstrapInterface;
42+
use sled_hardware::underlay::BootstrapInterface;
4343
use slog::Drain;
4444
use slog::Logger;
4545
use std::net::IpAddr;
@@ -348,10 +348,12 @@ impl BootstrapNetworking {
348348
async fn setup(config: &Config) -> Result<Self, StartError> {
349349
let link_for_mac =
350350
config.get_link().await.map_err(StartError::ConfigLink)?;
351-
let global_zone_bootstrap_ip = BootstrapInterface::GlobalZone
352-
.ip(&link_for_mac)
353-
.await
354-
.map_err(StartError::BootstrapLinkMac)?;
351+
let global_zone_bootstrap_ip = underlay::bootstrap_ip(
352+
BootstrapInterface::GlobalZone,
353+
&link_for_mac,
354+
)
355+
.await
356+
.map_err(StartError::BootstrapLinkMac)?;
355357

356358
let bootstrap_etherstub =
357359
Dladm::ensure_etherstub(dladm::BOOTSTRAP_ETHERSTUB_NAME)
@@ -388,10 +390,12 @@ impl BootstrapNetworking {
388390
IpAddr::V6(addr) => addr,
389391
};
390392

391-
let switch_zone_bootstrap_ip = BootstrapInterface::SwitchZone
392-
.ip(&link_for_mac)
393-
.await
394-
.map_err(StartError::BootstrapLinkMac)?;
393+
let switch_zone_bootstrap_ip = underlay::bootstrap_ip(
394+
BootstrapInterface::SwitchZone,
395+
&link_for_mac,
396+
)
397+
.await
398+
.map_err(StartError::BootstrapLinkMac)?;
395399

396400
let underlay_etherstub =
397401
Dladm::ensure_etherstub(dladm::UNDERLAY_ETHERSTUB_NAME)

sled-hardware/src/underlay.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,30 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5-
//! Finding the underlay network physical links and address objects.
5+
//! Finding the underlay network physical links and address objects,
6+
//! and deriving bootstrap IP addresses.
7+
8+
use std::net::Ipv6Addr;
69

710
use crate::is_oxide_sled;
811
use illumos_utils::addrobj;
912
use illumos_utils::addrobj::AddrObject;
13+
use illumos_utils::dladm;
1014
use illumos_utils::dladm::CHELSIO_LINK_PREFIX;
1115
use illumos_utils::dladm::Dladm;
1216
use illumos_utils::dladm::FindPhysicalLinkError;
1317
use illumos_utils::dladm::GetLinkpropError;
1418
use illumos_utils::dladm::PhysicalLink;
1519
use illumos_utils::dladm::SetLinkpropError;
1620
use illumos_utils::zone::Zones;
21+
use omicron_common::api::external::MacAddr;
22+
23+
#[doc(inline)]
24+
pub use sled_hardware_types::underlay::BOOTSTRAP_MASK;
25+
#[doc(inline)]
26+
pub use sled_hardware_types::underlay::BOOTSTRAP_PREFIX;
27+
#[doc(inline)]
28+
pub use sled_hardware_types::underlay::BootstrapInterface;
1729

1830
#[derive(thiserror::Error, Debug)]
1931
pub enum Error {
@@ -99,3 +111,47 @@ pub async fn ensure_links_have_global_zone_link_local_v6_addresses(
99111

100112
Ok(addr_objs)
101113
}
114+
115+
// TODO(https://github.com/oxidecomputer/omicron/issues/945): This address
116+
// could be randomly generated when it no longer needs to be durable.
117+
/// Derive the bootstrap IP address for the given interface by reading
118+
/// the MAC address of the given physical link.
119+
pub async fn bootstrap_ip(
120+
interface: BootstrapInterface,
121+
link: &PhysicalLink,
122+
) -> Result<Ipv6Addr, dladm::GetMacError> {
123+
let mac = Dladm::get_mac(link).await?;
124+
Ok(mac_to_bootstrap_ip(mac, interface.interface_id()))
125+
}
126+
127+
fn mac_to_bootstrap_ip(mac: MacAddr, interface_id: u64) -> Ipv6Addr {
128+
let mac_bytes = mac.into_array();
129+
assert_eq!(6, mac_bytes.len());
130+
131+
Ipv6Addr::new(
132+
BOOTSTRAP_PREFIX,
133+
(u16::from(mac_bytes[0]) << 8) | u16::from(mac_bytes[1]),
134+
(u16::from(mac_bytes[2]) << 8) | u16::from(mac_bytes[3]),
135+
(u16::from(mac_bytes[4]) << 8) | u16::from(mac_bytes[5]),
136+
((interface_id >> 48) & 0xffff).try_into().unwrap(),
137+
((interface_id >> 32) & 0xffff).try_into().unwrap(),
138+
((interface_id >> 16) & 0xffff).try_into().unwrap(),
139+
(interface_id & 0xffff).try_into().unwrap(),
140+
)
141+
}
142+
143+
#[cfg(test)]
144+
mod tests {
145+
use super::*;
146+
use macaddr::MacAddr6;
147+
148+
#[test]
149+
fn test_mac_to_bootstrap_ip() {
150+
let mac = MacAddr("a8:40:25:10:00:01".parse::<MacAddr6>().unwrap());
151+
152+
assert_eq!(
153+
mac_to_bootstrap_ip(mac, 1),
154+
"fdb0:a840:2510:1::1".parse::<Ipv6Addr>().unwrap(),
155+
);
156+
}
157+
}

sled-hardware/types/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ workspace = true
99

1010
[dependencies]
1111
daft.workspace = true
12-
illumos-utils.workspace = true
13-
omicron-common.workspace = true
1412
schemars.workspace = true
1513
serde.workspace = true
1614
slog.workspace = true
@@ -20,7 +18,6 @@ test-strategy = { workspace = true, optional = true }
2018
proptest = { workspace = true, optional = true }
2119

2220
[dev-dependencies]
23-
macaddr.workspace = true
2421
proptest.workspace = true
2522
test-strategy.workspace = true
2623

sled-hardware/types/src/underlay.rs

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5-
use illumos_utils::dladm;
6-
use illumos_utils::dladm::Dladm;
7-
use illumos_utils::dladm::PhysicalLink;
8-
use omicron_common::api::external::MacAddr;
9-
use std::net::Ipv6Addr;
10-
115
/// Initial octet of IPv6 for bootstrap addresses.
126
pub const BOOTSTRAP_PREFIX: u16 = 0xfdb0;
137

@@ -27,46 +21,4 @@ impl BootstrapInterface {
2721
BootstrapInterface::SwitchZone => 2,
2822
}
2923
}
30-
31-
// TODO(https://github.com/oxidecomputer/omicron/issues/945): This address
32-
// could be randomly generated when it no longer needs to be durable.
33-
pub async fn ip(
34-
self,
35-
link: &PhysicalLink,
36-
) -> Result<Ipv6Addr, dladm::GetMacError> {
37-
let mac = Dladm::get_mac(link).await?;
38-
Ok(mac_to_bootstrap_ip(mac, self.interface_id()))
39-
}
40-
}
41-
42-
fn mac_to_bootstrap_ip(mac: MacAddr, interface_id: u64) -> Ipv6Addr {
43-
let mac_bytes = mac.into_array();
44-
assert_eq!(6, mac_bytes.len());
45-
46-
Ipv6Addr::new(
47-
BOOTSTRAP_PREFIX,
48-
(u16::from(mac_bytes[0]) << 8) | u16::from(mac_bytes[1]),
49-
(u16::from(mac_bytes[2]) << 8) | u16::from(mac_bytes[3]),
50-
(u16::from(mac_bytes[4]) << 8) | u16::from(mac_bytes[5]),
51-
((interface_id >> 48) & 0xffff).try_into().unwrap(),
52-
((interface_id >> 32) & 0xffff).try_into().unwrap(),
53-
((interface_id >> 16) & 0xffff).try_into().unwrap(),
54-
(interface_id & 0xfff).try_into().unwrap(),
55-
)
56-
}
57-
58-
#[cfg(test)]
59-
mod tests {
60-
use super::*;
61-
use macaddr::MacAddr6;
62-
63-
#[test]
64-
fn test_mac_to_bootstrap_ip() {
65-
let mac = MacAddr("a8:40:25:10:00:01".parse::<MacAddr6>().unwrap());
66-
67-
assert_eq!(
68-
mac_to_bootstrap_ip(mac, 1),
69-
"fdb0:a840:2510:1::1".parse::<Ipv6Addr>().unwrap(),
70-
);
71-
}
7224
}

0 commit comments

Comments
 (0)