Skip to content
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

Perform rack network initialization earlier in rack setup #3276

Merged
merged 3 commits into from
Jun 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ anyhow.workspace = true
api_identity.workspace = true
backoff.workspace = true
chrono.workspace = true
dpd-client.workspace = true
dropshot.workspace = true
futures.workspace = true
hex.workspace = true
Expand Down
63 changes: 63 additions & 0 deletions common/src/api/internal/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,69 @@ pub struct RackNetworkConfig {
pub infra_ip_last: String,
/// Switchport to use for external connectivity
pub uplink_port: String,
/// Speed for the Switchport
pub uplink_port_speed: PortSpeed,
/// Forward Error Correction setting for the uplink port
pub uplink_port_fec: PortFec,
/// IP Address to apply to switchport (must be in infra_ip pool)
pub uplink_ip: String,
}

/// Switchport Speed options
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum PortSpeed {
#[serde(alias = "0G")]
Speed0G,
#[serde(alias = "1G")]
Speed1G,
#[serde(alias = "10G")]
Speed10G,
#[serde(alias = "25G")]
Speed25G,
#[serde(alias = "40G")]
Speed40G,
#[serde(alias = "50G")]
Speed50G,
#[serde(alias = "100G")]
Speed100G,
#[serde(alias = "200G")]
Speed200G,
#[serde(alias = "400G")]
Speed400G,
}

impl From<PortSpeed> for dpd_client::types::PortSpeed {
fn from(value: PortSpeed) -> Self {
match value {
PortSpeed::Speed0G => dpd_client::types::PortSpeed::Speed0G,
PortSpeed::Speed1G => dpd_client::types::PortSpeed::Speed1G,
PortSpeed::Speed10G => dpd_client::types::PortSpeed::Speed10G,
PortSpeed::Speed25G => dpd_client::types::PortSpeed::Speed25G,
PortSpeed::Speed40G => dpd_client::types::PortSpeed::Speed40G,
PortSpeed::Speed50G => dpd_client::types::PortSpeed::Speed50G,
PortSpeed::Speed100G => dpd_client::types::PortSpeed::Speed100G,
PortSpeed::Speed200G => dpd_client::types::PortSpeed::Speed200G,
PortSpeed::Speed400G => dpd_client::types::PortSpeed::Speed400G,
}
}
}

/// Switchport FEC options
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum PortFec {
Firecode,
None,
Rs,
}

impl From<PortFec> for dpd_client::types::PortFec {
fn from(value: PortFec) -> Self {
match value {
PortFec::Firecode => dpd_client::types::PortFec::Firecode,
PortFec::None => dpd_client::types::PortFec::None,
PortFec::Rs => dpd_client::types::PortFec::Rs,
}
}
}
5 changes: 4 additions & 1 deletion ddm-admin-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ impl Client {
Self::new(log, SocketAddrV6::new(Ipv6Addr::LOCALHOST, DDMD_PORT, 0, 0))
}

fn new(log: &Logger, ddmd_addr: SocketAddrV6) -> Result<Self, DdmError> {
pub fn new(
log: &Logger,
ddmd_addr: SocketAddrV6,
) -> Result<Self, DdmError> {
let dur = std::time::Duration::from_secs(60);
let log =
log.new(slog::o!("DdmAdminClient" => SocketAddr::V6(ddmd_addr)));
Expand Down
1 change: 1 addition & 0 deletions docs/how-to-run.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ gateway_ip = "192.168.1.199" <--- ip address of your default gateway / router
infra_ip_first = "192.168.1.30" <--- first address of pool used for rack networking
infra_ip_last = "192.168.1.50" <--- last address of pool used for rack networking
uplink_port = "qsfp0" <--- for "softnpu" environments, this will always be "qsfp0"
uplink_port_speed = "40G" <--- uplink interface speed
uplink_ip = "192.168.1.32" <--- address to assign to the uplink port
----

Expand Down
52 changes: 52 additions & 0 deletions nexus-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,55 @@ impl From<&omicron_common::api::internal::shared::SourceNatConfig>
Self { ip: r.ip, first_port: r.first_port, last_port: r.last_port }
}
}

impl From<omicron_common::api::internal::shared::PortSpeed>
for types::PortSpeed
{
fn from(value: omicron_common::api::internal::shared::PortSpeed) -> Self {
match value {
omicron_common::api::internal::shared::PortSpeed::Speed0G => {
types::PortSpeed::Speed0G
}
omicron_common::api::internal::shared::PortSpeed::Speed1G => {
types::PortSpeed::Speed1G
}
omicron_common::api::internal::shared::PortSpeed::Speed10G => {
types::PortSpeed::Speed10G
}
omicron_common::api::internal::shared::PortSpeed::Speed25G => {
types::PortSpeed::Speed25G
}
omicron_common::api::internal::shared::PortSpeed::Speed40G => {
types::PortSpeed::Speed40G
}
omicron_common::api::internal::shared::PortSpeed::Speed50G => {
types::PortSpeed::Speed50G
}
omicron_common::api::internal::shared::PortSpeed::Speed100G => {
types::PortSpeed::Speed100G
}
omicron_common::api::internal::shared::PortSpeed::Speed200G => {
types::PortSpeed::Speed200G
}
omicron_common::api::internal::shared::PortSpeed::Speed400G => {
types::PortSpeed::Speed400G
}
}
}
}

impl From<omicron_common::api::internal::shared::PortFec> for types::PortFec {
fn from(value: omicron_common::api::internal::shared::PortFec) -> Self {
match value {
omicron_common::api::internal::shared::PortFec::Firecode => {
types::PortFec::Firecode
}
omicron_common::api::internal::shared::PortFec::None => {
types::PortFec::None
}
omicron_common::api::internal::shared::PortFec::Rs => {
types::PortFec::Rs
}
}
}
}
87 changes: 4 additions & 83 deletions nexus/src/app/rack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,6 @@ use crate::db::lookup::LookupPath;
use crate::external_api::params::CertificateCreate;
use crate::external_api::shared::ServiceUsingCertificate;
use crate::internal_api::params::RackInitializationRequest;
use dpd_client::types::Ipv6Entry;
use dpd_client::types::LinkCreate;
use dpd_client::types::LinkId;
use dpd_client::types::LinkSettings;
use dpd_client::types::PortFec;
use dpd_client::types::PortId;
use dpd_client::types::PortSettings;
use dpd_client::types::PortSpeed;
use dpd_client::types::RouteSettingsV4;
use dpd_client::Ipv4Cidr;
use nexus_db_model::DnsGroup;
use nexus_db_model::InitialDnsGroup;
use nexus_db_queries::context::OpContext;
Expand Down Expand Up @@ -48,13 +38,9 @@ use omicron_common::api::external::Name;
use omicron_common::api::external::NameOrId;
use std::collections::HashMap;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::net::Ipv6Addr;
use std::str::FromStr;
use uuid::Uuid;

use super::sagas::NEXUS_DPD_TAG;

impl super::Nexus {
pub async fn racks_list(
&self,
Expand Down Expand Up @@ -238,9 +224,9 @@ impl super::Nexus {
// Currently calling some of the apis directly, but should we be using sagas
// going forward via self.run_saga()? Note that self.create_runnable_saga and
// self.execute_saga are currently not available within this scope.
info!(self.log, "checking for rack networking configuration");
info!(self.log, "Checking for Rack Network Configuration");
if let Some(rack_network_config) = &request.rack_network_config {
info!(self.log, "configuring rack networking");
info!(self.log, "Recording Rack Network Configuration");
let address_lot_name =
Name::from_str("initial-infra").map_err(|e| {
Error::internal_error(&format!(
Expand Down Expand Up @@ -366,20 +352,6 @@ impl super::Nexus {
.await?;
}

let body = Ipv6Entry {
addr: Ipv6Addr::from_str("fd00:99::1").map_err(|e| {
Error::internal_error(&format!(
"failed to parse `fd00:99::1` as `Ipv6Addr`: {e}"
))
})?,
tag: NEXUS_DPD_TAG.into(),
};
self.dpd_client.loopback_ipv6_create(&body).await.map_err(|e| {
Error::internal_error(&format!(
"unable to create inital switch loopback address: {e}"
))
})?;

let name = Name::from_str("default-uplink").map_err(|e| {
Error::internal_error(&format!(
"unable to use `default-uplink` as `Name`: {e}"
Expand Down Expand Up @@ -455,59 +427,8 @@ impl super::Nexus {
.await?;
}

let mut dpd_port_settings = PortSettings {
tag: NEXUS_DPD_TAG.into(),
links: HashMap::new(),
v4_routes: HashMap::new(),
v6_routes: HashMap::new(),
};

// TODO handle breakouts
// https://github.com/oxidecomputer/omicron/issues/3062
let link_id = LinkId(0);
let addr = IpAddr::from_str(&rack_network_config.uplink_ip)
.map_err(|e| {
Error::internal_error(&format!(
"unable to parse rack_network_config.uplink_up as IpAddr: {e}"))
})?;

let link_settings = LinkSettings {
// TODO Allow user to configure link properties
// https://github.com/oxidecomputer/omicron/issues/3061
params: LinkCreate {
autoneg: false,
kr: false,
fec: PortFec::None,
speed: PortSpeed::Speed100G,
},
addrs: vec![addr],
};

dpd_port_settings.links.insert(link_id.to_string(), link_settings);

let port_id: PortId = PortId::from_str(&rack_network_config.uplink_port)
.map_err(|e| Error::internal_error(
&format!("could not use value provided to rack_network_config.uplink_port as PortID: {e}")
))?;

let nexthop = Some(Ipv4Addr::from_str(&rack_network_config.gateway_ip)
.map_err(|e| Error::internal_error(
&format!("unable to parse rack_network_config.gateway_ip as Ipv4Addr: {e}")
))?);

dpd_port_settings.v4_routes.insert(
Ipv4Cidr {
prefix: Ipv4Addr::from_str("0.0.0.0").unwrap(),
prefix_len: 0,
}
.to_string(),
RouteSettingsV4 { link_id: link_id.0, nexthop },
);

self.dpd_client
.port_settings_apply(&port_id, &dpd_port_settings)
.await
.map_err(|e| Error::internal_error(&format!("unable to apply initial uplink port configuration: {e}")))?;
// TODO - https://github.com/oxidecomputer/omicron/issues/3277
// record port speed
};

Ok(())
Expand Down
44 changes: 43 additions & 1 deletion openapi/bootstrap-agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,30 @@
"description": "Password hashes must be in PHC (Password Hashing Competition) string format. Passwords must be hashed with Argon2id. Password hashes may be rejected if the parameters appear not to be secure enough.",
"type": "string"
},
"PortFec": {
"description": "Switchport FEC options",
"type": "string",
"enum": [
"firecode",
"none",
"rs"
]
},
"PortSpeed": {
"description": "Switchport Speed options",
"type": "string",
"enum": [
"speed0_g",
"speed1_g",
"speed10_g",
"speed25_g",
"speed40_g",
"speed50_g",
"speed100_g",
"speed200_g",
"speed400_g"
]
},
"RackInitializeRequest": {
"description": "Configuration for the \"rack setup service\".\n\nThe Rack Setup Service should be responsible for one-time setup actions, such as CockroachDB placement and initialization. Without operator intervention, however, these actions need a way to be automated in our deployment.",
"type": "object",
Expand Down Expand Up @@ -387,14 +411,32 @@
"uplink_port": {
"description": "Switchport to use for external connectivity",
"type": "string"
},
"uplink_port_fec": {
"description": "Forward Error Correction setting for the uplink port",
"allOf": [
{
"$ref": "#/components/schemas/PortFec"
}
]
},
"uplink_port_speed": {
"description": "Speed for the Switchport",
"allOf": [
{
"$ref": "#/components/schemas/PortSpeed"
}
]
}
},
"required": [
"gateway_ip",
"infra_ip_first",
"infra_ip_last",
"uplink_ip",
"uplink_port"
"uplink_port",
"uplink_port_fec",
"uplink_port_speed"
]
},
"RecoverySiloConfig": {
Expand Down
Loading