From 9a47816e9de77f870561fee781f68b90f583b17e Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Tue, 7 May 2024 15:08:32 -0700 Subject: [PATCH 01/23] building --- Cargo.lock | 121 ++++++++++++------ Cargo.toml | 11 +- clients/nexus-client/Cargo.toml | 1 + clients/nexus-client/src/lib.rs | 20 +-- clients/sled-agent-client/Cargo.toml | 1 + clients/sled-agent-client/src/lib.rs | 30 +++-- common/Cargo.toml | 1 + common/src/address.rs | 116 ++++++++--------- common/src/api/external/mod.rs | 27 +++- common/src/api/internal/nexus.rs | 4 +- common/src/api/internal/shared.rs | 43 ++----- illumos-utils/Cargo.toml | 1 + illumos-utils/src/opte/firewall_rules.rs | 10 +- illumos-utils/src/opte/port_manager.rs | 3 +- internal-dns/src/resolver.rs | 2 +- nexus/db-model/Cargo.toml | 1 + nexus/db-model/src/ipv6net.rs | 6 +- nexus/db-model/src/lib.rs | 6 +- nexus/db-model/src/vpc.rs | 1 + nexus/db-model/src/vpc_subnet.rs | 4 +- nexus/reconfigurator/planning/Cargo.toml | 1 + .../planning/src/blueprint_builder/builder.rs | 2 +- nexus/types/Cargo.toml | 1 + nexus/types/src/external_api/params.rs | 5 +- nexus/types/src/external_api/views.rs | 5 +- sled-agent/Cargo.toml | 1 + sled-agent/src/bootstrap/early_networking.rs | 11 +- sled-agent/src/rack_setup/plan/service.rs | 28 +--- sled-agent/src/services.rs | 6 +- wicket-common/Cargo.toml | 1 + wicket-common/src/rack_setup.rs | 2 +- 31 files changed, 256 insertions(+), 216 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a362c64eef..cd27ed0156 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -416,9 +416,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -2044,12 +2044,11 @@ dependencies = [ [[package]] name = "dropshot" -version = "0.9.1-dev" -source = "git+https://github.com/oxidecomputer/dropshot?branch=main#29ae98d1f909c6832661408a4c03f929e8afa6e9" +version = "0.10.1-dev" dependencies = [ "async-stream", "async-trait", - "base64 0.21.7", + "base64 0.22.1", "bytes", "camino", "chrono", @@ -2057,7 +2056,7 @@ dependencies = [ "dropshot_endpoint", "form_urlencoded", "futures", - "hostname", + "hostname 0.4.0", "http 0.2.12", "hyper 0.14.28", "indexmap 2.2.6", @@ -2065,10 +2064,10 @@ dependencies = [ "openapiv3", "paste", "percent-encoding", - "proc-macro2", "rustls 0.22.4", "rustls-pemfile 2.1.2", "schemars", + "scopeguard", "serde", "serde_json", "serde_path_to_error", @@ -2082,7 +2081,7 @@ dependencies = [ "tokio", "tokio-rustls 0.25.0", "toml 0.8.12", - "usdt 0.3.5", + "usdt 0.5.0", "uuid", "version_check", "waitgroup", @@ -2090,8 +2089,7 @@ dependencies = [ [[package]] name = "dropshot_endpoint" -version = "0.9.1-dev" -source = "git+https://github.com/oxidecomputer/dropshot?branch=main#29ae98d1f909c6832661408a4c03f929e8afa6e9" +version = "0.10.1-dev" dependencies = [ "proc-macro2", "quote", @@ -2239,7 +2237,7 @@ dependencies = [ "anstyle", "anyhow", "async-trait", - "base64 0.22.0", + "base64 0.22.1", "chrono", "clap", "colored", @@ -2696,7 +2694,7 @@ dependencies = [ name = "gateway-client" version = "0.1.0" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "chrono", "gateway-messages", "omicron-workspace-hack", @@ -3131,6 +3129,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "hostname" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" +dependencies = [ + "cfg-if", + "libc", + "windows 0.52.0", +] + [[package]] name = "http" version = "0.2.12" @@ -3296,7 +3305,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.5.6", "tokio", "tower-service", "tracing", @@ -3417,7 +3426,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows 0.48.0", ] [[package]] @@ -3504,6 +3513,7 @@ dependencies = [ "opte-ioctl", "oxide-vpc", "oxlog", + "oxnet", "regress", "schemars", "serde", @@ -4372,16 +4382,15 @@ dependencies = [ [[package]] name = "multer" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15d522be0a9c3e46fd2632e272d178f56387bdb5c9fbb3a36c649062e9b5219" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" dependencies = [ "bytes", "encoding_rs", "futures-util", "http 1.0.0", "httparse", - "log", "memchr", "mime", "spin 0.9.8", @@ -4477,6 +4486,7 @@ dependencies = [ "omicron-passwords", "omicron-uuid-kinds", "omicron-workspace-hack", + "oxnet", "progenitor", "regress", "reqwest", @@ -4533,6 +4543,7 @@ dependencies = [ "omicron-uuid-kinds", "omicron-workspace-hack", "once_cell", + "oxnet", "parse-display", "pq-sys", "rand 0.8.5", @@ -4560,7 +4571,7 @@ dependencies = [ "async-bb8-diesel", "async-trait", "authz-macros", - "base64 0.22.0", + "base64 0.22.1", "bb8", "camino", "camino-tempfile", @@ -4652,7 +4663,7 @@ name = "nexus-inventory" version = "0.1.0" dependencies = [ "anyhow", - "base64 0.22.0", + "base64 0.22.1", "chrono", "expectorate", "futures", @@ -4787,6 +4798,7 @@ dependencies = [ "omicron-test-utils", "omicron-uuid-kinds", "omicron-workspace-hack", + "oxnet", "proptest", "rand 0.8.5", "sled-agent-client", @@ -4886,7 +4898,7 @@ version = "0.1.0" dependencies = [ "anyhow", "api_identity", - "base64 0.22.0", + "base64 0.22.1", "chrono", "clap", "dns-service-client", @@ -4900,6 +4912,7 @@ dependencies = [ "omicron-uuid-kinds", "omicron-workspace-hack", "openssl", + "oxnet", "parse-display", "schemars", "serde", @@ -5222,6 +5235,7 @@ dependencies = [ "omicron-uuid-kinds", "omicron-workspace-hack", "once_cell", + "oxnet", "parse-display", "progenitor", "progenitor-client", @@ -5310,7 +5324,7 @@ name = "omicron-gateway" version = "0.1.0" dependencies = [ "anyhow", - "base64 0.22.0", + "base64 0.22.1", "camino", "clap", "dropshot", @@ -5356,7 +5370,7 @@ dependencies = [ "assert_matches", "async-bb8-diesel", "async-trait", - "base64 0.22.0", + "base64 0.22.1", "buf-list", "bytes", "camino", @@ -5594,7 +5608,7 @@ dependencies = [ "anyhow", "assert_matches", "async-trait", - "base64 0.22.0", + "base64 0.22.1", "bootstore", "bootstrap-agent-client", "bytes", @@ -5646,6 +5660,7 @@ dependencies = [ "oximeter", "oximeter-instruments", "oximeter-producer", + "oxnet", "pretty_assertions", "propolis-client 0.1.0 (git+https://github.com/oxidecomputer/propolis?rev=27e2789d381c0fcc237fbe30cec2ec66bd750c12)", "propolis-mock-server", @@ -5740,7 +5755,7 @@ dependencies = [ "aho-corasick", "anyhow", "base16ct", - "base64 0.22.0", + "base64 0.22.1", "bit-set", "bit-vec", "bitflags 1.3.2", @@ -6052,7 +6067,7 @@ name = "oxide-client" version = "0.1.0" dependencies = [ "anyhow", - "base64 0.22.0", + "base64 0.22.1", "chrono", "futures", "http 0.2.12", @@ -6278,6 +6293,15 @@ dependencies = [ "uuid", ] +[[package]] +name = "oxnet" +version = "0.1.0" +dependencies = [ + "schemars", + "serde", + "serde_json", +] + [[package]] name = "p256" version = "0.13.2" @@ -6531,7 +6555,7 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "serde", ] @@ -6979,7 +7003,6 @@ dependencies = [ [[package]] name = "progenitor" version = "0.6.0" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#0f0b1062f471f33d4d42273c03c4079f6ebf4ad9" dependencies = [ "progenitor-client", "progenitor-impl", @@ -6990,7 +7013,6 @@ dependencies = [ [[package]] name = "progenitor-client" version = "0.6.0" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#0f0b1062f471f33d4d42273c03c4079f6ebf4ad9" dependencies = [ "bytes", "futures-core", @@ -7004,7 +7026,6 @@ dependencies = [ [[package]] name = "progenitor-impl" version = "0.6.0" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#0f0b1062f471f33d4d42273c03c4079f6ebf4ad9" dependencies = [ "getopts", "heck 0.5.0", @@ -7026,7 +7047,6 @@ dependencies = [ [[package]] name = "progenitor-macro" version = "0.6.0" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#0f0b1062f471f33d4d42273c03c4079f6ebf4ad9" dependencies = [ "openapiv3", "proc-macro2", @@ -7337,7 +7357,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf2890aaef0aa82719a50e808de264f9484b74b442e1a3a0e5ee38243ac40bdb" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.5.1", ] [[package]] @@ -7631,7 +7651,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" dependencies = [ - "hostname", + "hostname 0.3.1", "quick-error", ] @@ -7992,7 +8012,7 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "rustls-pki-types", ] @@ -8104,7 +8124,7 @@ version = "0.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5da862a2115c0767681e28309a367dbd0a2366026948aae0272787e582d71eaf" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "bindgen", "chrono", "data-encoding", @@ -8278,9 +8298,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.199" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" dependencies = [ "serde_derive", ] @@ -8325,9 +8345,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ "proc-macro2", "quote", @@ -8655,6 +8675,7 @@ dependencies = [ "omicron-common", "omicron-uuid-kinds", "omicron-workspace-hack", + "oxnet", "progenitor", "regress", "reqwest", @@ -8763,7 +8784,7 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcaaf6e68789d3f0411f1e72bc443214ef252a1038b6e344836e50442541f190" dependencies = [ - "hostname", + "hostname 0.3.1", "slog", "slog-json", "time", @@ -10913,6 +10934,7 @@ dependencies = [ "omicron-common", "omicron-workspace-hack", "owo-colors", + "oxnet", "schemars", "serde", "serde_json", @@ -10950,7 +10972,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "base64 0.22.0", + "base64 0.22.1", "bootstrap-agent-client", "buf-list", "bytes", @@ -11088,6 +11110,25 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 12d2e954be..1bf410e085 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -288,6 +288,7 @@ omicron-certificates = { path = "certificates" } omicron-passwords = { path = "passwords" } omicron-workspace-hack = "0.1.0" oxlog = { path = "dev-tools/oxlog" } +oxnet = { path = "../oxnet", version = "0.1.0" } nexus-test-interface = { path = "nexus/test-interface" } nexus-test-utils-macros = { path = "nexus/test-utils-macros" } nexus-test-utils = { path = "nexus/test-utils" } @@ -619,8 +620,8 @@ opt-level = 3 # It's common during development to use a local copy of various complex # dependencies. If you want to use those, uncomment one of these blocks. # -#[patch."https://github.com/oxidecomputer/dropshot"] -#dropshot = { path = "../dropshot/dropshot" } +[patch."https://github.com/oxidecomputer/dropshot"] +dropshot = { path = "../dropshot/dropshot" } #[patch.crates-io] #steno = { path = "../steno" } #[patch."https://github.com/oxidecomputer/propolis"] @@ -638,9 +639,9 @@ opt-level = 3 # # Local client generation during development. # -#[patch."https://github.com/oxidecomputer/progenitor"] -#progenitor = { path = "../progenitor/progenitor" } -#progenitor-client = { path = "../progenitor/progenitor-client" } +[patch."https://github.com/oxidecomputer/progenitor"] +progenitor = { path = "../progenitor/progenitor" } +progenitor-client = { path = "../progenitor/progenitor-client" } #[patch."https://github.com/oxidecomputer/typify"] #typify = { path = "../typify/typify" } diff --git a/clients/nexus-client/Cargo.toml b/clients/nexus-client/Cargo.toml index fd6df6919f..1344782beb 100644 --- a/clients/nexus-client/Cargo.toml +++ b/clients/nexus-client/Cargo.toml @@ -11,6 +11,7 @@ ipnetwork.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-passwords.workspace = true +oxnet.workspace = true progenitor.workspace = true regress.workspace = true reqwest = { workspace = true, features = ["rustls-tls", "stream"] } diff --git a/clients/nexus-client/src/lib.rs b/clients/nexus-client/src/lib.rs index 92cc3ff27e..9115c6d417 100644 --- a/clients/nexus-client/src/lib.rs +++ b/clients/nexus-client/src/lib.rs @@ -421,33 +421,27 @@ impl TryFrom } } -impl TryFrom<&omicron_common::api::external::Ipv4Net> for types::Ipv4Net { +impl TryFrom<&oxnet::Ipv4Net> for types::Ipv4Net { type Error = String; - fn try_from( - net: &omicron_common::api::external::Ipv4Net, - ) -> Result { + fn try_from(net: &oxnet::Ipv4Net) -> Result { types::Ipv4Net::try_from(net.to_string()).map_err(|e| e.to_string()) } } -impl TryFrom<&omicron_common::api::external::Ipv6Net> for types::Ipv6Net { +impl TryFrom<&oxnet::Ipv6Net> for types::Ipv6Net { type Error = String; - fn try_from( - net: &omicron_common::api::external::Ipv6Net, - ) -> Result { + fn try_from(net: &oxnet::Ipv6Net) -> Result { types::Ipv6Net::try_from(net.to_string()).map_err(|e| e.to_string()) } } -impl TryFrom<&omicron_common::api::external::IpNet> for types::IpNet { +impl TryFrom<&oxnet::IpNet> for types::IpNet { type Error = String; - fn try_from( - net: &omicron_common::api::external::IpNet, - ) -> Result { - use omicron_common::api::external::IpNet; + fn try_from(net: &oxnet::IpNet) -> Result { + use oxnet::IpNet; match net { IpNet::V4(v4) => types::Ipv4Net::try_from(v4).map(types::IpNet::V4), IpNet::V6(v6) => types::Ipv6Net::try_from(v6).map(types::IpNet::V6), diff --git a/clients/sled-agent-client/Cargo.toml b/clients/sled-agent-client/Cargo.toml index 1f5453d298..9f5926b49b 100644 --- a/clients/sled-agent-client/Cargo.toml +++ b/clients/sled-agent-client/Cargo.toml @@ -19,4 +19,5 @@ slog.workspace = true uuid.workspace = true omicron-workspace-hack.workspace = true omicron-uuid-kinds.workspace = true +oxnet.workspace = true serde_json.workspace = true diff --git a/clients/sled-agent-client/src/lib.rs b/clients/sled-agent-client/src/lib.rs index bfb97ec9cd..6c74411c46 100644 --- a/clients/sled-agent-client/src/lib.rs +++ b/clients/sled-agent-client/src/lib.rs @@ -46,7 +46,6 @@ progenitor::generate_api!( Name = omicron_common::api::external::Name, SwitchLocation = omicron_common::api::external::SwitchLocation, ImportExportPolicy = omicron_common::api::external::ImportExportPolicy, - Ipv6Network = ipnetwork::Ipv6Network, IpNetwork = ipnetwork::IpNetwork, PortFec = omicron_common::api::internal::shared::PortFec, PortSpeed = omicron_common::api::internal::shared::PortSpeed, @@ -412,24 +411,23 @@ impl From for omicron_common::api::external::DiskState { } } -impl From for types::Ipv4Net { - fn from(n: omicron_common::api::external::Ipv4Net) -> Self { +impl From for types::Ipv4Net { + fn from(n: oxnet::Ipv4Net) -> Self { Self::try_from(n.to_string()).unwrap_or_else(|e| panic!("{}: {}", n, e)) } } -impl From for types::Ipv6Net { - fn from(n: omicron_common::api::external::Ipv6Net) -> Self { +impl From for types::Ipv6Net { + fn from(n: oxnet::Ipv6Net) -> Self { Self::try_from(n.to_string()).unwrap_or_else(|e| panic!("{}: {}", n, e)) } } -impl From for types::IpNet { - fn from(s: omicron_common::api::external::IpNet) -> Self { - use omicron_common::api::external::IpNet; +impl From for types::IpNet { + fn from(s: oxnet::IpNet) -> Self { match s { - IpNet::V4(v4) => Self::V4(v4.into()), - IpNet::V6(v6) => Self::V6(v6.into()), + oxnet::IpNet::V4(v4) => Self::V4(v4.into()), + oxnet::IpNet::V6(v6) => Self::V6(v6.into()), } } } @@ -440,14 +438,14 @@ impl From for types::Ipv4Net { } } -impl From for ipnetwork::Ipv4Network { +impl From for oxnet::Ipv4Net { fn from(n: types::Ipv4Net) -> Self { n.parse().unwrap() } } -impl From for types::Ipv4Network { - fn from(n: ipnetwork::Ipv4Network) -> Self { +impl From for types::Ipv4Network { + fn from(n: oxnet::Ipv4Net) -> Self { Self::try_from(n.to_string()).unwrap_or_else(|e| panic!("{}: {}", n, e)) } } @@ -483,6 +481,12 @@ impl From for ipnetwork::IpNetwork { } } +impl From for ipnetwork::Ipv4Network { + fn from(n: types::Ipv4Net) -> Self { + n.parse().unwrap() + } +} + impl From for types::Ipv4Net { fn from(n: std::net::Ipv4Addr) -> Self { Self::try_from(format!("{n}/32")) diff --git a/common/Cargo.toml b/common/Cargo.toml index 23499039e6..8d2320f7f6 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -26,6 +26,7 @@ macaddr.workspace = true mg-admin-client.workspace = true dpd-client.workspace = true omicron-uuid-kinds.workspace = true +oxnet.workspace = true proptest = { workspace = true, optional = true } rand.workspace = true reqwest = { workspace = true, features = ["rustls-tls", "stream"] } diff --git a/common/src/address.rs b/common/src/address.rs index 817070d399..d92a84d2f2 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -7,9 +7,10 @@ //! This addressing functionality is shared by both initialization services //! and Nexus, who need to agree upon addressing schemes. -use crate::api::external::{self, Error, Ipv4Net, Ipv6Net}; +use crate::api::external::{self, Error}; use ipnetwork::{Ipv4Network, Ipv6Network}; use once_cell::sync::Lazy; +use oxnet::{Ipv4Net, Ipv6Net}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV6}; @@ -72,6 +73,12 @@ pub const WICKETD_NEXUS_PROXY_PORT: u16 = 12229; pub const NTP_PORT: u16 = 123; +/// The length for all VPC IPv6 prefixes +pub const VPC_IPV6_PREFIX_LENGTH: u8 = 48; + +/// The prefix length for all VPC Sunets +pub const VPC_SUBNET_IPV6_PREFIX_LENGTH: u8 = 64; + // The number of ports available to an SNAT IP. // Note that for static NAT, this value isn't used, and all ports are available. // @@ -104,61 +111,50 @@ pub const NUM_SOURCE_NAT_PORTS: u16 = 1 << 14; // Furthermore, all the below *_OPTE_IPV6_SUBNET constants are // /64's within this prefix. pub static SERVICE_VPC_IPV6_PREFIX: Lazy = Lazy::new(|| { - Ipv6Net( - Ipv6Network::new( - Ipv6Addr::new(0xfd77, 0xe9d2, 0x9cd9, 0, 0, 0, 0, 0), - Ipv6Net::VPC_IPV6_PREFIX_LENGTH, - ) - .unwrap(), + Ipv6Net::new( + Ipv6Addr::new(0xfd77, 0xe9d2, 0x9cd9, 0, 0, 0, 0, 0), + VPC_IPV6_PREFIX_LENGTH, ) + .unwrap() }); /// The IPv4 subnet for External DNS OPTE ports. -pub static DNS_OPTE_IPV4_SUBNET: Lazy = Lazy::new(|| { - Ipv4Net(Ipv4Network::new(Ipv4Addr::new(172, 30, 1, 0), 24).unwrap()) -}); +pub static DNS_OPTE_IPV4_SUBNET: Lazy = + Lazy::new(|| Ipv4Net::new(Ipv4Addr::new(172, 30, 1, 0), 24).unwrap()); /// The IPv6 subnet for External DNS OPTE ports. pub static DNS_OPTE_IPV6_SUBNET: Lazy = Lazy::new(|| { - Ipv6Net( - Ipv6Network::new( - Ipv6Addr::new(0xfd77, 0xe9d2, 0x9cd9, 1, 0, 0, 0, 0), - Ipv6Net::VPC_SUBNET_IPV6_PREFIX_LENGTH, - ) - .unwrap(), + Ipv6Net::new( + Ipv6Addr::new(0xfd77, 0xe9d2, 0x9cd9, 1, 0, 0, 0, 0), + VPC_SUBNET_IPV6_PREFIX_LENGTH, ) + .unwrap() }); /// The IPv4 subnet for Nexus OPTE ports. -pub static NEXUS_OPTE_IPV4_SUBNET: Lazy = Lazy::new(|| { - Ipv4Net(Ipv4Network::new(Ipv4Addr::new(172, 30, 2, 0), 24).unwrap()) -}); +pub static NEXUS_OPTE_IPV4_SUBNET: Lazy = + Lazy::new(|| Ipv4Net::new(Ipv4Addr::new(172, 30, 2, 0), 24).unwrap()); /// The IPv6 subnet for Nexus OPTE ports. pub static NEXUS_OPTE_IPV6_SUBNET: Lazy = Lazy::new(|| { - Ipv6Net( - Ipv6Network::new( - Ipv6Addr::new(0xfd77, 0xe9d2, 0x9cd9, 2, 0, 0, 0, 0), - Ipv6Net::VPC_SUBNET_IPV6_PREFIX_LENGTH, - ) - .unwrap(), + Ipv6Net::new( + Ipv6Addr::new(0xfd77, 0xe9d2, 0x9cd9, 2, 0, 0, 0, 0), + VPC_SUBNET_IPV6_PREFIX_LENGTH, ) + .unwrap() }); /// The IPv4 subnet for Boundary NTP OPTE ports. -pub static NTP_OPTE_IPV4_SUBNET: Lazy = Lazy::new(|| { - Ipv4Net(Ipv4Network::new(Ipv4Addr::new(172, 30, 3, 0), 24).unwrap()) -}); +pub static NTP_OPTE_IPV4_SUBNET: Lazy = + Lazy::new(|| Ipv4Net::new(Ipv4Addr::new(172, 30, 3, 0), 24).unwrap()); /// The IPv6 subnet for Boundary NTP OPTE ports. pub static NTP_OPTE_IPV6_SUBNET: Lazy = Lazy::new(|| { - Ipv6Net( - Ipv6Network::new( - Ipv6Addr::new(0xfd77, 0xe9d2, 0x9cd9, 3, 0, 0, 0, 0), - Ipv6Net::VPC_SUBNET_IPV6_PREFIX_LENGTH, - ) - .unwrap(), + Ipv6Net::new( + Ipv6Addr::new(0xfd77, 0xe9d2, 0x9cd9, 3, 0, 0, 0, 0), + VPC_SUBNET_IPV6_PREFIX_LENGTH, ) + .unwrap() }); // Anycast is a mechanism in which a single IP address is shared by multiple @@ -197,24 +193,26 @@ pub struct Ipv6Subnet { impl Ipv6Subnet { pub fn new(addr: Ipv6Addr) -> Self { + // TODO should Ipv6Net either validate that the address is canonical or + // mask it appropriately? i.e. rendering these steps unnecessary? // Create a network with the compile-time prefix length. - let net = Ipv6Network::new(addr, N).unwrap(); + let net = Ipv6Net::new(addr, N).unwrap(); // Ensure the address is set to within-prefix only components. - let net = Ipv6Network::new(net.network(), N).unwrap(); - Self { net: Ipv6Net(net) } + let net = Ipv6Net::new(net.network(), N).unwrap(); + Self { net } } /// Returns the underlying network. - pub fn net(&self) -> Ipv6Network { - self.net.0 + pub fn net(&self) -> Ipv6Net { + self.net } } impl From for Ipv6Subnet { fn from(net: Ipv6Network) -> Self { // Ensure the address is set to within-prefix only components. - let net = Ipv6Network::new(net.network(), N).unwrap(); - Self { net: Ipv6Net(net) } + let net = Ipv6Net::new(net.network(), N).unwrap(); + Self { net } } } @@ -252,24 +250,26 @@ impl DnsSubnet { /// Returns the DNS server address within the subnet. /// /// This is the first address within the subnet. - pub fn dns_address(&self) -> Ipv6Network { - Ipv6Network::new( - self.subnet.net().iter().nth(DNS_ADDRESS_INDEX).unwrap(), - SLED_PREFIX, - ) - .unwrap() + pub fn dns_address(&self) -> Ipv6Addr { + // Ipv6Network::new( + // self.subnet.net().iter().nth(DNS_ADDRESS_INDEX).unwrap(), + // SLED_PREFIX, + // ) + // .unwrap() + todo!() } /// Returns the address which the Global Zone should create /// to be able to contact the DNS server. /// /// This is the second address within the subnet. - pub fn gz_address(&self) -> Ipv6Network { - Ipv6Network::new( - self.subnet.net().iter().nth(GZ_ADDRESS_INDEX).unwrap(), - SLED_PREFIX, - ) - .unwrap() + pub fn gz_address(&self) -> Ipv6Addr { + // Ipv6Network::new( + // self.subnet.net().iter().nth(GZ_ADDRESS_INDEX).unwrap(), + // SLED_PREFIX, + // ) + // .unwrap() + todo!() } } @@ -281,7 +281,7 @@ pub struct ReservedRackSubnet(pub Ipv6Subnet); impl ReservedRackSubnet { /// Returns the subnet for the reserved rack subnet. pub fn new(subnet: Ipv6Subnet) -> Self { - ReservedRackSubnet(Ipv6Subnet::::new(subnet.net().ip())) + ReservedRackSubnet(Ipv6Subnet::::new(subnet.net().addr())) } /// Returns the DNS addresses from this reserved rack subnet. @@ -308,7 +308,7 @@ pub fn get_internal_dns_server_addresses(addr: Ipv6Addr) -> Vec { &reserved_rack_subnet.get_dns_subnets()[0..DNS_REDUNDANCY]; dns_subnets .iter() - .map(|dns_subnet| IpAddr::from(dns_subnet.dns_address().ip())) + .map(|dns_subnet| IpAddr::from(dns_subnet.dns_address())) .collect() } @@ -680,7 +680,7 @@ mod test { assert_eq!( // Note that these bits (indicating the rack) are zero. // vv - "fd00:1122:3344:0000::/56".parse::().unwrap(), + "fd00:1122:3344:0000::/56".parse::().unwrap(), rack_subnet.0.net(), ); @@ -690,11 +690,11 @@ mod test { // The DNS address and GZ address should be only differing by one. assert_eq!( - "fd00:1122:3344:0001::1/64".parse::().unwrap(), + "fd00:1122:3344:0001::1".parse::().unwrap(), dns_subnets[0].dns_address(), ); assert_eq!( - "fd00:1122:3344:0001::2/64".parse::().unwrap(), + "fd00:1122:3344:0001::2".parse::().unwrap(), dns_subnets[0].gz_address(), ); } diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index 9e0966f949..41c8970489 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -1222,7 +1222,7 @@ impl DiskState { /// An `Ipv4Net` represents a IPv4 subnetwork, including the address and network mask. #[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Eq, Serialize)] -pub struct Ipv4Net(pub ipnetwork::Ipv4Network); +struct Ipv4Net(pub ipnetwork::Ipv4Network); impl Ipv4Net { /// Return `true` if this IPv4 subnetwork is from an RFC 1918 private @@ -1283,7 +1283,7 @@ impl JsonSchema for Ipv4Net { /// An `Ipv6Net` represents a IPv6 subnetwork, including the address and network mask. #[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Eq, Serialize)] -pub struct Ipv6Net(pub ipnetwork::Ipv6Network); +struct Ipv6Net(pub ipnetwork::Ipv6Network); impl Ipv6Net { /// The length for all VPC IPv6 prefixes @@ -1317,6 +1317,25 @@ impl Ipv6Net { } } +pub trait Ipv6NetExt { + /// Return `true` if this subnetwork is a valid VPC prefix. + /// + /// This checks that the subnet is a unique local address, and has the VPC + /// prefix length required. + fn is_vpc_prefix(&self) -> bool; +} + +impl Ipv6NetExt for oxnet::Ipv6Net { + fn is_vpc_prefix(&self) -> bool { + /// The length for all VPC IPv6 prefixes + pub const VPC_IPV6_PREFIX_LENGTH: u8 = 48; + + // /// The prefix length for all VPC subnets + // pub const VPC_SUBNET_IPV6_PREFIX_LENGTH: u8 = 64; + self.is_unique_local() && self.prefix() == VPC_IPV6_PREFIX_LENGTH + } +} + impl std::ops::Deref for Ipv6Net { type Target = ipnetwork::Ipv6Network; fn deref(&self) -> &Self::Target { @@ -1421,7 +1440,7 @@ impl JsonSchema for Ipv6Net { /// An `IpNet` represents an IP network, either IPv4 or IPv6. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum IpNet { +enum IpNet { V4(Ipv4Net), V6(Ipv6Net), } @@ -3199,7 +3218,7 @@ pub enum ImportExportPolicy { /// Do not perform any filtering. #[default] NoFiltering, - Allow(Vec), + Allow(Vec), } #[cfg(test)] diff --git a/common/src/api/internal/nexus.rs b/common/src/api/internal/nexus.rs index 5a44921c26..83bfc3704a 100644 --- a/common/src/api/internal/nexus.rs +++ b/common/src/api/internal/nexus.rs @@ -6,7 +6,7 @@ use crate::api::external::{ ByteCount, DiskState, Generation, Hostname, InstanceCpuCount, - InstanceState, IpNet, SemverVersion, Vni, + InstanceState, SemverVersion, Vni, }; use chrono::{DateTime, Utc}; use omicron_uuid_kinds::DownstairsRegionKind; @@ -261,7 +261,7 @@ mod tests { #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)] #[serde(tag = "type", content = "value", rename_all = "snake_case")] pub enum HostIdentifier { - Ip(IpNet), + Ip(oxnet::IpNet), Vpc(Vni), } diff --git a/common/src/api/internal/shared.rs b/common/src/api/internal/shared.rs index 6bd40d3ff0..c75ffe62da 100644 --- a/common/src/api/internal/shared.rs +++ b/common/src/api/internal/shared.rs @@ -6,9 +6,10 @@ use crate::{ address::NUM_SOURCE_NAT_PORTS, - api::external::{self, BfdMode, ImportExportPolicy, IpNet, Name}, + api::external::{self, BfdMode, ImportExportPolicy, Name}, }; use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network}; +use oxnet::IpNet; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{ @@ -53,7 +54,7 @@ pub struct NetworkInterface { pub name: external::Name, pub ip: IpAddr, pub mac: external::MacAddr, - pub subnet: external::IpNet, + pub subnet: IpNet, pub vni: external::Vni, pub primary: bool, pub slot: u8, @@ -527,13 +528,6 @@ impl TryFrom> for AllowedSourceIps { } } -impl TryFrom<&[IpNetwork]> for AllowedSourceIps { - type Error = &'static str; - fn try_from(list: &[IpNetwork]) -> Result { - IpAllowList::try_from(list).map(Self::List) - } -} - /// A non-empty allowlist of IP subnets. #[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] #[serde(try_from = "Vec", into = "Vec")] @@ -580,23 +574,10 @@ impl TryFrom> for IpAllowList { } } -impl TryFrom<&[IpNetwork]> for IpAllowList { - type Error = &'static str; - fn try_from(list: &[IpNetwork]) -> Result { - if list.is_empty() { - return Err("IP allowlist must not be empty"); - } - Ok(Self(list.iter().copied().map(Into::into).collect())) - } -} - #[cfg(test)] mod tests { - use crate::api::{ - external::{IpNet, Ipv4Net, Ipv6Net}, - internal::shared::AllowedSourceIps, - }; - use ipnetwork::{Ipv4Network, Ipv6Network}; + use crate::api::internal::shared::AllowedSourceIps; + use oxnet::{IpNet, Ipv4Net, Ipv6Net}; use std::net::{Ipv4Addr, Ipv6Addr}; #[test] @@ -608,17 +589,17 @@ mod tests { assert_eq!( parsed, AllowedSourceIps::try_from(vec![ - IpNet::from(Ipv4Addr::LOCALHOST), - IpNet::V4(Ipv4Net( - Ipv4Network::new(Ipv4Addr::new(10, 0, 0, 0), 24).unwrap() - )), - IpNet::V6(Ipv6Net( - Ipv6Network::new( + Ipv4Net::host_net(Ipv4Addr::LOCALHOST).into(), + IpNet::V4( + Ipv4Net::new(Ipv4Addr::new(10, 0, 0, 0), 24).unwrap() + ), + IpNet::V6( + Ipv6Net::new( Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 1), 64 ) .unwrap() - )), + ), ]) .unwrap() ); diff --git a/illumos-utils/Cargo.toml b/illumos-utils/Cargo.toml index cd13e4a8a6..452b83ba1a 100644 --- a/illumos-utils/Cargo.toml +++ b/illumos-utils/Cargo.toml @@ -22,6 +22,7 @@ omicron-common.workspace = true omicron-uuid-kinds.workspace = true oxide-vpc.workspace = true oxlog.workspace = true +oxnet.workspace = true schemars.workspace = true serde.workspace = true slog.workspace = true diff --git a/illumos-utils/src/opte/firewall_rules.rs b/illumos-utils/src/opte/firewall_rules.rs index 02882a226b..abb81ca927 100644 --- a/illumos-utils/src/opte/firewall_rules.rs +++ b/illumos-utils/src/opte/firewall_rules.rs @@ -7,7 +7,6 @@ use crate::opte::params::VpcFirewallRule; use crate::opte::Vni; use macaddr::MacAddr6; -use omicron_common::api::external::IpNet; use omicron_common::api::external::VpcFirewallRuleAction; use omicron_common::api::external::VpcFirewallRuleDirection; use omicron_common::api::external::VpcFirewallRuleProtocol; @@ -27,6 +26,7 @@ use oxide_vpc::api::Ipv6PrefixLen; use oxide_vpc::api::Ports; use oxide_vpc::api::ProtoFilter; use oxide_vpc::api::Protocol; +use oxnet::IpNet; trait FromVpcFirewallRule { fn action(&self) -> FirewallAction; @@ -68,22 +68,22 @@ impl FromVpcFirewallRule for VpcFirewallRule { HostIdentifier::Ip(IpNet::V4(net)) if net.prefix() == 32 => { - Address::Ip(IpAddr::Ip4(net.ip().into())) + Address::Ip(IpAddr::Ip4(net.addr().into())) } HostIdentifier::Ip(IpNet::V4(net)) => { Address::Subnet(IpCidr::Ip4(Ipv4Cidr::new( - net.ip().into(), + net.addr().into(), Ipv4PrefixLen::new(net.prefix()).unwrap(), ))) } HostIdentifier::Ip(IpNet::V6(net)) if net.prefix() == 128 => { - Address::Ip(IpAddr::Ip6(net.ip().into())) + Address::Ip(IpAddr::Ip6(net.addr().into())) } HostIdentifier::Ip(IpNet::V6(net)) => { Address::Subnet(IpCidr::Ip6(Ipv6Cidr::new( - net.ip().into(), + net.addr().into(), Ipv6PrefixLen::new(net.prefix()).unwrap(), ))) } diff --git a/illumos-utils/src/opte/port_manager.rs b/illumos-utils/src/opte/port_manager.rs index 03c51c321d..ffc92b87b2 100644 --- a/illumos-utils/src/opte/port_manager.rs +++ b/illumos-utils/src/opte/port_manager.rs @@ -107,7 +107,8 @@ impl PortManager { ) -> Result<(Port, PortTicket), Error> { let mac = *nic.mac; let vni = Vni::new(nic.vni).unwrap(); - let subnet = IpNetwork::from(nic.subnet); + let subnet = + IpNetwork::new(nic.subnet.addr(), nic.subnet.prefix()).unwrap(); let vpc_subnet = IpCidr::from(subnet); let gateway = Gateway::from_subnet(&subnet); diff --git a/internal-dns/src/resolver.rs b/internal-dns/src/resolver.rs index a7796f559a..cf5def01c5 100644 --- a/internal-dns/src/resolver.rs +++ b/internal-dns/src/resolver.rs @@ -118,7 +118,7 @@ impl Resolver { .get_dns_subnets() .into_iter() .map(|dns_subnet| { - let ip_addr = IpAddr::V6(dns_subnet.dns_address().ip()); + let ip_addr = IpAddr::V6(dns_subnet.dns_address()); SocketAddr::new(ip_addr, DNS_PORT) }) .collect() diff --git a/nexus/db-model/Cargo.toml b/nexus/db-model/Cargo.toml index bfe75377c5..e4800af05c 100644 --- a/nexus/db-model/Cargo.toml +++ b/nexus/db-model/Cargo.toml @@ -19,6 +19,7 @@ macaddr.workspace = true newtype_derive.workspace = true omicron-uuid-kinds.workspace = true once_cell.workspace = true +oxnet.workspace = true parse-display.workspace = true # See omicron-rpaths for more about the "pq-sys" dependency. pq-sys = "*" diff --git a/nexus/db-model/src/ipv6net.rs b/nexus/db-model/src/ipv6net.rs index d516b67ed9..6de57955ec 100644 --- a/nexus/db-model/src/ipv6net.rs +++ b/nexus/db-model/src/ipv6net.rs @@ -29,10 +29,10 @@ use crate::RequestAddressError; Deserialize, )] #[diesel(sql_type = sql_types::Inet)] -pub struct Ipv6Net(pub external::Ipv6Net); +pub struct Ipv6Net(pub oxnet::Ipv6Net); -NewtypeFrom! { () pub struct Ipv6Net(external::Ipv6Net); } -NewtypeDeref! { () pub struct Ipv6Net(external::Ipv6Net); } +NewtypeFrom! { () pub struct Ipv6Net(oxnet::Ipv6Net); } +NewtypeDeref! { () pub struct Ipv6Net(oxnet::Ipv6Net); } impl Ipv6Net { /// Generate a random subnetwork from this one, of the given prefix length. diff --git a/nexus/db-model/src/lib.rs b/nexus/db-model/src/lib.rs index c7b495b094..fe05e6b62a 100644 --- a/nexus/db-model/src/lib.rs +++ b/nexus/db-model/src/lib.rs @@ -432,9 +432,9 @@ mod tests { use ipnetwork::Ipv4Network; use ipnetwork::Ipv6Network; use omicron_common::api::external::IdentityMetadataCreateParams; - use omicron_common::api::external::IpNet; - use omicron_common::api::external::Ipv4Net; - use omicron_common::api::external::Ipv6Net; + use oxnet::IpNet; + use oxnet::Ipv4Net; + use oxnet::Ipv6Net; use std::net::IpAddr; use std::net::Ipv4Addr; use std::net::Ipv6Addr; diff --git a/nexus/db-model/src/vpc.rs b/nexus/db-model/src/vpc.rs index 8a4dc0e349..00faebe656 100644 --- a/nexus/db-model/src/vpc.rs +++ b/nexus/db-model/src/vpc.rs @@ -14,6 +14,7 @@ use nexus_types::external_api::params; use nexus_types::external_api::views; use nexus_types::identity::Resource; use omicron_common::api::external; +use omicron_common::api::external::Ipv6NetExt; use serde::Deserialize; use serde::Serialize; use uuid::Uuid; diff --git a/nexus/db-model/src/vpc_subnet.rs b/nexus/db-model/src/vpc_subnet.rs index 407c933ef2..f3c90a908e 100644 --- a/nexus/db-model/src/vpc_subnet.rs +++ b/nexus/db-model/src/vpc_subnet.rs @@ -50,8 +50,8 @@ impl VpcSubnet { subnet_id: Uuid, vpc_id: Uuid, identity: external::IdentityMetadataCreateParams, - ipv4_block: external::Ipv4Net, - ipv6_block: external::Ipv6Net, + ipv4_block: oxnet::Ipv4Net, + ipv6_block: oxnet::Ipv6Net, ) -> Self { let identity = VpcSubnetIdentity::new(subnet_id, identity); Self { diff --git a/nexus/reconfigurator/planning/Cargo.toml b/nexus/reconfigurator/planning/Cargo.toml index d31832482d..fd8e66ebd0 100644 --- a/nexus/reconfigurator/planning/Cargo.toml +++ b/nexus/reconfigurator/planning/Cargo.toml @@ -17,6 +17,7 @@ nexus-inventory.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true +oxnet.workspace = true rand.workspace = true sled-agent-client.workspace = true slog.workspace = true diff --git a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs index dc8b1452a7..0ab61a50f4 100644 --- a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs +++ b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs @@ -39,7 +39,6 @@ use omicron_common::address::NEXUS_OPTE_IPV6_SUBNET; use omicron_common::address::NTP_PORT; use omicron_common::address::SLED_RESERVED_ADDRESSES; use omicron_common::api::external::Generation; -use omicron_common::api::external::IpNet; use omicron_common::api::external::MacAddr; use omicron_common::api::external::Vni; use omicron_common::api::internal::shared::NetworkInterface; @@ -51,6 +50,7 @@ use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; +use oxnet::IpNet; use rand::rngs::StdRng; use rand::SeedableRng; use slog::debug; diff --git a/nexus/types/Cargo.toml b/nexus/types/Cargo.toml index a67b639197..e2f7d1ea92 100644 --- a/nexus/types/Cargo.toml +++ b/nexus/types/Cargo.toml @@ -14,6 +14,7 @@ humantime.workspace = true ipnetwork.workspace = true omicron-uuid-kinds.workspace = true openssl.workspace = true +oxnet.workspace = true parse-display.workspace = true schemars = { workspace = true, features = ["chrono", "uuid1"] } serde.workspace = true diff --git a/nexus/types/src/external_api/params.rs b/nexus/types/src/external_api/params.rs index 1b252c77cb..3f53503cc2 100644 --- a/nexus/types/src/external_api/params.rs +++ b/nexus/types/src/external_api/params.rs @@ -11,9 +11,10 @@ use chrono::{DateTime, Utc}; use omicron_common::api::external::{ AddressLotKind, AllowedSourceIps, BfdMode, BgpPeer, ByteCount, Hostname, IdentityMetadataCreateParams, IdentityMetadataUpdateParams, - InstanceCpuCount, IpNet, Ipv4Net, Ipv6Net, LinkFec, LinkSpeed, Name, - NameOrId, PaginationOrder, RouteDestination, RouteTarget, SemverVersion, + InstanceCpuCount, LinkFec, LinkSpeed, Name, NameOrId, PaginationOrder, + RouteDestination, RouteTarget, SemverVersion, }; +use oxnet::{IpNet, Ipv4Net, Ipv6Net}; use schemars::JsonSchema; use serde::{ de::{self, Visitor}, diff --git a/nexus/types/src/external_api/views.rs b/nexus/types/src/external_api/views.rs index e0ba36f160..a13d96cf09 100644 --- a/nexus/types/src/external_api/views.rs +++ b/nexus/types/src/external_api/views.rs @@ -13,9 +13,10 @@ use chrono::DateTime; use chrono::Utc; use omicron_common::api::external::{ AllowedSourceIps as ExternalAllowedSourceIps, ByteCount, Digest, Error, - IdentityMetadata, InstanceState, Ipv4Net, Ipv6Net, Name, ObjectIdentity, - RoleName, SimpleIdentity, + IdentityMetadata, InstanceState, Name, ObjectIdentity, RoleName, + SimpleIdentity, }; +use oxnet::{Ipv4Net, Ipv6Net}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; diff --git a/sled-agent/Cargo.toml b/sled-agent/Cargo.toml index 998d83725a..a92f2107ab 100644 --- a/sled-agent/Cargo.toml +++ b/sled-agent/Cargo.toml @@ -53,6 +53,7 @@ once_cell.workspace = true oximeter.workspace = true oximeter-instruments.workspace = true oximeter-producer.workspace = true +oxnet.workspace = true propolis-client.workspace = true propolis-mock-server.workspace = true # Only used by the simulated sled agent rand = { workspace = true, features = ["getrandom"] } diff --git a/sled-agent/src/bootstrap/early_networking.rs b/sled-agent/src/bootstrap/early_networking.rs index 2714c220c7..84891b6cbc 100644 --- a/sled-agent/src/bootstrap/early_networking.rs +++ b/sled-agent/src/bootstrap/early_networking.rs @@ -23,7 +23,7 @@ use mg_admin_client::types::{ use mg_admin_client::Client as MgdClient; use omicron_common::address::DENDRITE_PORT; use omicron_common::address::{MGD_PORT, MGS_PORT}; -use omicron_common::api::external::{BfdMode, ImportExportPolicy, IpNet}; +use omicron_common::api::external::{BfdMode, ImportExportPolicy}; use omicron_common::api::internal::shared::{ BgpConfig, PortConfigV1, PortFec, PortSpeed, RackNetworkConfig, RackNetworkConfigV1, SwitchLocation, UplinkConfig, @@ -34,6 +34,7 @@ use omicron_common::backoff::{ }; use omicron_common::OMICRON_DPD_TAG; use omicron_ddm_admin_client::DdmError; +use oxnet::IpNet; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use slog::Logger; @@ -516,11 +517,11 @@ impl<'a> EarlyNetworkSetup<'a> { .map(|x| match x { IpNet::V4(p) => Prefix::V4(Prefix4 { length: p.prefix(), - value: p.ip(), + value: p.addr(), }), IpNet::V6(p) => Prefix::V6(Prefix6 { length: p.prefix(), - value: p.ip(), + value: p.addr(), }), }) .collect(), @@ -538,11 +539,11 @@ impl<'a> EarlyNetworkSetup<'a> { .map(|x| match x { IpNet::V4(p) => Prefix::V4(Prefix4 { length: p.prefix(), - value: p.ip(), + value: p.addr(), }), IpNet::V6(p) => Prefix::V6(Prefix6 { length: p.prefix(), - value: p.ip(), + value: p.addr(), }), }) .collect(), diff --git a/sled-agent/src/rack_setup/plan/service.rs b/sled-agent/src/rack_setup/plan/service.rs index b4a6fe76f6..6e3c525567 100644 --- a/sled-agent/src/rack_setup/plan/service.rs +++ b/sled-agent/src/rack_setup/plan/service.rs @@ -384,11 +384,11 @@ impl Plan { &reserved_rack_subnet.get_dns_subnets()[0..DNS_REDUNDANCY]; let rack_dns_servers = dns_subnets .into_iter() - .map(|dns_subnet| dns_subnet.dns_address().ip().into()) + .map(|dns_subnet| dns_subnet.dns_address().into()) .collect::>(); for i in 0..dns_subnets.len() { let dns_subnet = &dns_subnets[i]; - let ip = dns_subnet.dns_address().ip(); + let ip = dns_subnet.dns_address(); let sled = { let which_sled = sled_allocator.next().ok_or(PlanError::NotEnoughSleds)?; @@ -419,7 +419,7 @@ impl Plan { }, http_address, dns_address, - gz_address: dns_subnet.gz_address().ip(), + gz_address: dns_subnet.gz_address(), gz_address_index: i.try_into().expect("Giant indices?"), }, }); @@ -960,40 +960,26 @@ impl ServicePortBuilder { let external_dns_ips = config.external_dns_ips.clone().into_iter(); let dns_v4_ips = Box::new( - DNS_OPTE_IPV4_SUBNET - .0 - .iter() - .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), + DNS_OPTE_IPV4_SUBNET.iter().skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), ); let dns_v6_ips = Box::new( - DNS_OPTE_IPV6_SUBNET - .0 - .iter() - .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), + DNS_OPTE_IPV6_SUBNET.iter().skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), ); let nexus_v4_ips = Box::new( NEXUS_OPTE_IPV4_SUBNET - .0 .iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), ); let nexus_v6_ips = Box::new( NEXUS_OPTE_IPV6_SUBNET - .0 .iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), ); let ntp_v4_ips = Box::new( - NTP_OPTE_IPV4_SUBNET - .0 - .iter() - .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), + NTP_OPTE_IPV4_SUBNET.iter().skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), ); let ntp_v6_ips = Box::new( - NTP_OPTE_IPV6_SUBNET - .0 - .iter() - .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), + NTP_OPTE_IPV6_SUBNET.iter().skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), ); Self { internal_services_ip_pool, diff --git a/sled-agent/src/services.rs b/sled-agent/src/services.rs index c9a5014402..3374328dfe 100644 --- a/sled-agent/src/services.rs +++ b/sled-agent/src/services.rs @@ -2543,7 +2543,7 @@ impl ServiceManager { ); smfh.setprop( "config/rack-subnet", - &rack_subnet.net().ip().to_string(), + &rack_subnet.net().addr().to_string(), )?; } @@ -3995,12 +3995,12 @@ impl ServiceManager { info!( self.inner.log, "configuring wicketd"; - "rack_subnet" => %rack_subnet.net().ip(), + "rack_subnet" => %rack_subnet.net().addr(), ); smfh.setprop( "config/rack-subnet", - &rack_subnet.net().ip().to_string(), + &rack_subnet.net().addr().to_string(), )?; smfh.refresh()?; diff --git a/wicket-common/Cargo.toml b/wicket-common/Cargo.toml index 385cd5ab0a..c90c42ca6a 100644 --- a/wicket-common/Cargo.toml +++ b/wicket-common/Cargo.toml @@ -8,6 +8,7 @@ license = "MPL-2.0" anyhow.workspace = true omicron-common.workspace = true owo-colors.workspace = true +oxnet.workspace = true gateway-client.workspace = true ipnetwork.workspace = true maplit.workspace = true diff --git a/wicket-common/src/rack_setup.rs b/wicket-common/src/rack_setup.rs index 5e89bfdde2..9221153398 100644 --- a/wicket-common/src/rack_setup.rs +++ b/wicket-common/src/rack_setup.rs @@ -9,7 +9,6 @@ pub use gateway_client::types::SpType as GatewaySpType; use ipnetwork::IpNetwork; use omicron_common::address; use omicron_common::api::external::ImportExportPolicy; -use omicron_common::api::external::IpNet; use omicron_common::api::external::Name; use omicron_common::api::external::SwitchLocation; use omicron_common::api::internal::shared::AllowedSourceIps; @@ -21,6 +20,7 @@ use omicron_common::api::internal::shared::RouteConfig; use omicron_common::update::ArtifactHash; use owo_colors::OwoColorize; use owo_colors::Style; +use oxnet::IpNet; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; From e160e67dfeb8b57688420e0a31be2ddcff3c8cb0 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 8 May 2024 11:30:35 -0700 Subject: [PATCH 02/23] cargo lock fix --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index cd27ed0156..d5b33ffd63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7357,7 +7357,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf2890aaef0aa82719a50e808de264f9484b74b442e1a3a0e5ee38243ac40bdb" dependencies = [ - "rand_core 0.5.1", + "rand_core 0.6.4", ] [[package]] From 5a1f70ac26de3299d18de8e1440178e74df1ff85 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 8 May 2024 13:03:14 -0700 Subject: [PATCH 03/23] progress --- Cargo.lock | 4 +++ common/src/api/external/mod.rs | 18 ++++++------- common/src/api/internal/shared.rs | 18 +++++++++++++ nexus/db-model/src/ipv4_nat_entry.rs | 4 +-- nexus/db-model/src/ipv4net.rs | 13 +++++----- nexus/db-model/src/ipv6net.rs | 17 ++++++------ nexus/db-model/src/lib.rs | 17 +++++------- nexus/db-model/src/network_interface.rs | 2 +- nexus/db-model/src/vpc.rs | 26 +++++++++---------- nexus/db-queries/Cargo.toml | 1 + .../src/db/datastore/network_interface.rs | 4 +-- .../src/db/datastore/switch_port.rs | 2 +- nexus/db-queries/src/db/datastore/vpc.rs | 4 +-- .../src/db/queries/network_interface.rs | 6 ++--- nexus/db-queries/src/db/queries/vpc_subnet.rs | 18 ++++++++----- nexus/defaults/Cargo.toml | 1 + nexus/defaults/src/lib.rs | 26 ++++++++----------- nexus/networking/Cargo.toml | 1 + nexus/networking/src/firewall_rules.rs | 7 ++--- .../planning/src/blueprint_builder/builder.rs | 2 -- wicket/src/ui/panes/rack_setup.rs | 4 +-- wicketd/src/rss_config.rs | 2 +- 22 files changed, 107 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5b33ffd63..f9d4bdf172 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4613,6 +4613,7 @@ dependencies = [ "openssl", "oso", "oximeter", + "oxnet", "paste", "pem", "petgraph", @@ -4654,6 +4655,7 @@ dependencies = [ "omicron-common", "omicron-workspace-hack", "once_cell", + "oxnet", "rand 0.8.5", "serde_json", ] @@ -4733,6 +4735,7 @@ dependencies = [ "nexus-db-queries", "omicron-common", "omicron-workspace-hack", + "oxnet", "reqwest", "sled-agent-client", "slog", @@ -6297,6 +6300,7 @@ dependencies = [ name = "oxnet" version = "0.1.0" dependencies = [ + "ipnetwork", "schemars", "serde", "serde_json", diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index 41c8970489..07ca2d72f5 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -1912,7 +1912,7 @@ pub enum VpcFirewallRuleTarget { /// The rule applies to a specific IP address Ip(IpAddr), /// The rule applies to a specific IP subnet - IpNet(IpNet), + IpNet(oxnet::IpNet), // Tags not yet implemented // Tag(Name), } @@ -1943,7 +1943,7 @@ pub enum VpcFirewallRuleHostFilter { /// The rule applies to traffic from/to a specific IP address Ip(IpAddr), /// The rule applies to traffic from/to a specific IP subnet - IpNet(IpNet), + IpNet(oxnet::IpNet), // TODO: Internet gateways not yet implemented // #[display("inetgw:{0}")] // InternetGateway(Name), @@ -2451,7 +2451,7 @@ pub struct LoopbackAddress { pub switch_location: String, /// The loopback IP address and prefix length. - pub address: IpNet, + pub address: oxnet::IpNet, } /// A switch port represents a physical external port on a rack switch. @@ -2693,7 +2693,7 @@ pub struct LldpConfig { pub system_description: String, /// THE LLDP management IP TLV. - pub management_ip: IpNet, + pub management_ip: oxnet::IpNet, } /// Describes the kind of an switch interface. @@ -2760,10 +2760,10 @@ pub struct SwitchPortRouteConfig { pub interface_name: String, /// The route's destination network. - pub dst: IpNet, + pub dst: oxnet::IpNet, /// The route's gateway address. - pub gw: IpNet, + pub gw: oxnet::IpNet, /// The VLAN identifier for the route. Use this if the gateway is reachable /// over an 802.1Q tagged L2 segment. @@ -2892,7 +2892,7 @@ pub struct BgpAnnouncement { pub address_lot_block_id: Uuid, /// The IP network being announced. - pub network: IpNet, + pub network: oxnet::IpNet, } /// An IP address configuration for a port settings object. @@ -2905,7 +2905,7 @@ pub struct SwitchPortAddressConfig { pub address_lot_block_id: Uuid, /// The IP address and prefix. - pub address: IpNet, + pub address: oxnet::IpNet, /// The interface name this address belongs to. // TODO: https://github.com/oxidecomputer/omicron/issues/3050 @@ -3065,7 +3065,7 @@ impl AggregateBgpMessageHistory { #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq)] pub struct BgpImportedRouteIpv4 { /// The destination network prefix. - pub prefix: Ipv4Net, + pub prefix: oxnet::Ipv4Net, /// The nexthop the prefix is reachable through. pub nexthop: Ipv4Addr, diff --git a/common/src/api/internal/shared.rs b/common/src/api/internal/shared.rs index c75ffe62da..6e12d35c53 100644 --- a/common/src/api/internal/shared.rs +++ b/common/src/api/internal/shared.rs @@ -528,6 +528,13 @@ impl TryFrom> for AllowedSourceIps { } } +impl TryFrom<&[ipnetwork::IpNetwork]> for AllowedSourceIps { + type Error = &'static str; + fn try_from(list: &[ipnetwork::IpNetwork]) -> Result { + IpAllowList::try_from(list).map(Self::List) + } +} + /// A non-empty allowlist of IP subnets. #[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] #[serde(try_from = "Vec", into = "Vec")] @@ -574,6 +581,17 @@ impl TryFrom> for IpAllowList { } } +impl TryFrom<&[ipnetwork::IpNetwork]> for IpAllowList { + type Error = &'static str; + + fn try_from(list: &[ipnetwork::IpNetwork]) -> Result { + if list.is_empty() { + return Err("IP allowlist must not be empty"); + } + Ok(Self(list.into_iter().map(|net| (*net).into()).collect())) + } +} + #[cfg(test)] mod tests { use crate::api::internal::shared::AllowedSourceIps; diff --git a/nexus/db-model/src/ipv4_nat_entry.rs b/nexus/db-model/src/ipv4_nat_entry.rs index c3763346c6..4ff1ee9171 100644 --- a/nexus/db-model/src/ipv4_nat_entry.rs +++ b/nexus/db-model/src/ipv4_nat_entry.rs @@ -81,10 +81,10 @@ pub struct Ipv4NatEntryView { impl From for Ipv4NatEntryView { fn from(value: Ipv4NatChange) -> Self { Self { - external_address: value.external_address.ip(), + external_address: value.external_address.addr(), first_port: value.first_port.into(), last_port: value.last_port.into(), - sled_address: value.sled_address.ip(), + sled_address: value.sled_address.addr(), vni: value.vni.0, mac: *value.mac, gen: value.version, diff --git a/nexus/db-model/src/ipv4net.rs b/nexus/db-model/src/ipv4net.rs index eaf8a6eed8..d57f28fd73 100644 --- a/nexus/db-model/src/ipv4net.rs +++ b/nexus/db-model/src/ipv4net.rs @@ -10,7 +10,6 @@ use diesel::serialize::{self, ToSql}; use diesel::sql_types; use ipnetwork::IpNetwork; use nexus_config::NUM_INITIAL_RESERVED_IP_ADDRESSES; -use omicron_common::api::external; use serde::Deserialize; use serde::Serialize; use std::net::Ipv4Addr; @@ -27,10 +26,10 @@ use std::net::Ipv4Addr; Deserialize, )] #[diesel(sql_type = sql_types::Inet)] -pub struct Ipv4Net(pub external::Ipv4Net); +pub struct Ipv4Net(pub oxnet::Ipv4Net); -NewtypeFrom! { () pub struct Ipv4Net(external::Ipv4Net); } -NewtypeDeref! { () pub struct Ipv4Net(external::Ipv4Net); } +NewtypeFrom! { () pub struct Ipv4Net(oxnet::Ipv4Net); } +NewtypeDeref! { () pub struct Ipv4Net(oxnet::Ipv4Net); } impl Ipv4Net { /// Check if an address is a valid user-requestable address for this subnet @@ -41,7 +40,7 @@ impl Ipv4Net { if !self.contains(addr) { return Err(RequestAddressError::OutsideSubnet( addr.into(), - self.0 .0.into(), + oxnet::IpNet::from(self.0).into(), )); } // Only the first N addresses are reserved @@ -67,7 +66,7 @@ impl ToSql for Ipv4Net { out: &mut serialize::Output<'a, '_, Pg>, ) -> serialize::Result { >::to_sql( - &IpNetwork::V4(*self.0), + &IpNetwork::V4(self.0.into()), &mut out.reborrow(), ) } @@ -81,7 +80,7 @@ where fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result { let inet = IpNetwork::from_sql(bytes)?; match inet { - IpNetwork::V4(net) => Ok(Ipv4Net(external::Ipv4Net(net))), + IpNetwork::V4(net) => Ok(Ipv4Net(net.into())), _ => Err("Expected IPV4".into()), } } diff --git a/nexus/db-model/src/ipv6net.rs b/nexus/db-model/src/ipv6net.rs index 6de57955ec..376d848c8e 100644 --- a/nexus/db-model/src/ipv6net.rs +++ b/nexus/db-model/src/ipv6net.rs @@ -9,7 +9,6 @@ use diesel::serialize::{self, ToSql}; use diesel::sql_types; use ipnetwork::IpNetwork; use nexus_config::NUM_INITIAL_RESERVED_IP_ADDRESSES; -use omicron_common::api::external; use rand::{rngs::StdRng, SeedableRng}; use serde::Deserialize; use serde::Serialize; @@ -72,17 +71,17 @@ impl Ipv6Net { let full_mask = !(u128::MAX >> prefix); // Get the existing network address and mask. - let network = u128::from_be_bytes(self.network().octets()); - let network_mask = u128::from_be_bytes(self.mask().octets()); + let network = u128::from(self.network()); + let network_mask = u128::from(self.mask()); // Take random bits _only_ where the new mask is set. let random_mask = full_mask ^ network_mask; let out = (network & network_mask) | (random & random_mask); - let addr = std::net::Ipv6Addr::from(out.to_be_bytes()); - let net = ipnetwork::Ipv6Network::new(addr, prefix) + let addr = std::net::Ipv6Addr::from(out); + let net = oxnet::Ipv6Net::new(addr, prefix) .expect("Failed to create random subnet"); - Some(Self(external::Ipv6Net(net))) + Some(Self(net)) } /// Check if an address is a valid user-requestable address for this subnet @@ -93,7 +92,7 @@ impl Ipv6Net { if !self.contains(addr) { return Err(RequestAddressError::OutsideSubnet( addr.into(), - self.0 .0.into(), + oxnet::IpNet::from(self.0).into(), )); } // Only the first N addresses are reserved @@ -114,7 +113,7 @@ impl ToSql for Ipv6Net { out: &mut serialize::Output<'a, '_, Pg>, ) -> serialize::Result { >::to_sql( - &IpNetwork::V6(self.0 .0), + &IpNetwork::V6(self.0.into()), &mut out.reborrow(), ) } @@ -128,7 +127,7 @@ where fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result { let inet = IpNetwork::from_sql(bytes)?; match inet { - IpNetwork::V6(net) => Ok(Ipv6Net(external::Ipv6Net(net))), + IpNetwork::V6(net) => Ok(Ipv6Net(net.into())), _ => Err("Expected IPV6".into()), } } diff --git a/nexus/db-model/src/lib.rs b/nexus/db-model/src/lib.rs index fe05e6b62a..ad4f9e8777 100644 --- a/nexus/db-model/src/lib.rs +++ b/nexus/db-model/src/lib.rs @@ -429,8 +429,6 @@ mod tests { use crate::RequestAddressError; use super::VpcSubnet; - use ipnetwork::Ipv4Network; - use ipnetwork::Ipv6Network; use omicron_common::api::external::IdentityMetadataCreateParams; use oxnet::IpNet; use oxnet::Ipv4Net; @@ -442,9 +440,8 @@ mod tests { #[test] fn test_vpc_subnet_check_requestable_addr() { - let ipv4_block = - Ipv4Net("192.168.0.0/16".parse::().unwrap()); - let ipv6_block = Ipv6Net("fd00::/48".parse::().unwrap()); + let ipv4_block = "192.168.0.0/16".parse::().unwrap(); + let ipv6_block = "fd00::/48".parse::().unwrap(); let identity = IdentityMetadataCreateParams { name: "net-test-vpc".parse().unwrap(), description: "A test VPC".parse().unwrap(), @@ -503,9 +500,7 @@ mod tests { #[test] fn test_ipv6_net_random_subnet() { - let base = super::Ipv6Net(Ipv6Net( - "fd00::/48".parse::().unwrap(), - )); + let base = super::Ipv6Net("fd00::/48".parse::().unwrap()); assert!( base.random_subnet(8).is_none(), "random_subnet() should fail when prefix is less than the base prefix" @@ -528,7 +523,7 @@ mod tests { "Host address portion should be 0" ); assert!( - base.is_supernet_of(subnet.0 .0), + base.is_supernet_of(&subnet.0), "random_subnet should generate an actual subnet" ); assert_eq!(base.random_subnet(base.prefix()), Some(base)); @@ -536,7 +531,7 @@ mod tests { #[test] fn test_ip_subnet_check_requestable_address() { - let subnet = super::Ipv4Net(Ipv4Net("192.168.0.0/16".parse().unwrap())); + let subnet = super::Ipv4Net("192.168.0.0/16".parse().unwrap()); subnet.check_requestable_addr("192.168.0.10".parse().unwrap()).unwrap(); subnet.check_requestable_addr("192.168.1.0".parse().unwrap()).unwrap(); let addr = "192.178.0.10".parse().unwrap(); @@ -561,7 +556,7 @@ mod tests { Err(RequestAddressError::Broadcast) ); - let subnet = super::Ipv6Net(Ipv6Net("fd00::/64".parse().unwrap())); + let subnet = super::Ipv6Net("fd00::/64".parse().unwrap()); subnet.check_requestable_addr("fd00::a".parse().unwrap()).unwrap(); assert_eq!( subnet.check_requestable_addr("fd00::1".parse().unwrap()), diff --git a/nexus/db-model/src/network_interface.rs b/nexus/db-model/src/network_interface.rs index ff774699d6..e2013f9bc7 100644 --- a/nexus/db-model/src/network_interface.rs +++ b/nexus/db-model/src/network_interface.rs @@ -71,7 +71,7 @@ pub struct NetworkInterface { impl NetworkInterface { pub fn into_internal( self, - subnet: external::IpNet, + subnet: oxnet::IpNet, ) -> internal::shared::NetworkInterface { internal::shared::NetworkInterface { id: self.id(), diff --git a/nexus/db-model/src/vpc.rs b/nexus/db-model/src/vpc.rs index 00faebe656..88879a0436 100644 --- a/nexus/db-model/src/vpc.rs +++ b/nexus/db-model/src/vpc.rs @@ -84,22 +84,20 @@ impl IncompleteVpc { params: params::VpcCreate, ) -> Result { let identity = VpcIdentity::new(vpc_id, params.identity); - let ipv6_prefix = IpNetwork::from( - match params.ipv6_prefix { - None => defaults::random_vpc_ipv6_prefix(), - Some(prefix) => { - if prefix.is_vpc_prefix() { - Ok(prefix) - } else { - Err(external::Error::invalid_request( - "VPC IPv6 address prefixes must be in the \ + let ipv6_prefix = oxnet::IpNet::from(match params.ipv6_prefix { + None => defaults::random_vpc_ipv6_prefix(), + Some(prefix) => { + if prefix.is_vpc_prefix() { + Ok(prefix) + } else { + Err(external::Error::invalid_request( + "VPC IPv6 address prefixes must be in the \ Unique Local Address range `fd00::/48` (RFD 4193)", - )) - } + )) } - }? - .0, - ); + } + }?) + .into(); Ok(Self { identity, project_id, diff --git a/nexus/db-queries/Cargo.toml b/nexus/db-queries/Cargo.toml index 354a2b0ac0..81f2501462 100644 --- a/nexus/db-queries/Cargo.toml +++ b/nexus/db-queries/Cargo.toml @@ -30,6 +30,7 @@ newtype_derive.workspace = true once_cell.workspace = true openssl.workspace = true oso.workspace = true +oxnet.workspace = true paste.workspace = true # See omicron-rpaths for more about the "pq-sys" dependency. pq-sys = "*" diff --git a/nexus/db-queries/src/db/datastore/network_interface.rs b/nexus/db-queries/src/db/datastore/network_interface.rs index 733e4ef32b..d7ef346cbd 100644 --- a/nexus/db-queries/src/db/datastore/network_interface.rs +++ b/nexus/db-queries/src/db/datastore/network_interface.rs @@ -68,9 +68,9 @@ impl From for omicron_common::api::internal::shared::NetworkInterface { nic: NicInfo, ) -> omicron_common::api::internal::shared::NetworkInterface { let ip_subnet = if nic.ip.is_ipv4() { - external::IpNet::V4(nic.ipv4_block.0) + oxnet::IpNet::V4(nic.ipv4_block.0) } else { - external::IpNet::V6(nic.ipv6_block.0) + oxnet::IpNet::V6(nic.ipv6_block.0) }; let kind = match nic.kind { NetworkInterfaceKind::Instance => { diff --git a/nexus/db-queries/src/db/datastore/switch_port.rs b/nexus/db-queries/src/db/datastore/switch_port.rs index 3f3717a9c4..edb16e95ac 100644 --- a/nexus/db-queries/src/db/datastore/switch_port.rs +++ b/nexus/db-queries/src/db/datastore/switch_port.rs @@ -529,7 +529,7 @@ impl DataStore { let (block, rsvd_block) = crate::db::datastore::address_lot::try_reserve_block( address_lot_id, - address.address.ip().into(), + address.address.addr().into(), // TODO: Should we allow anycast addresses for switch_ports? // anycast false, diff --git a/nexus/db-queries/src/db/datastore/vpc.rs b/nexus/db-queries/src/db/datastore/vpc.rs index 632ea501e3..34c18d39a4 100644 --- a/nexus/db-queries/src/db/datastore/vpc.rs +++ b/nexus/db-queries/src/db/datastore/vpc.rs @@ -1168,8 +1168,8 @@ impl DataStore { let mut result = BTreeMap::new(); for subnet in subnets { let entry = result.entry(subnet.name).or_insert_with(Vec::new); - entry.push(IpNetwork::V4(subnet.ipv4_block.0 .0)); - entry.push(IpNetwork::V6(subnet.ipv6_block.0 .0)); + entry.push(IpNetwork::V4(subnet.ipv4_block.0.into())); + entry.push(IpNetwork::V6(subnet.ipv6_block.0.into())); } Ok(result) } diff --git a/nexus/db-queries/src/db/queries/network_interface.rs b/nexus/db-queries/src/db/queries/network_interface.rs index a9cea9826a..02185183d0 100644 --- a/nexus/db-queries/src/db/queries/network_interface.rs +++ b/nexus/db-queries/src/db/queries/network_interface.rs @@ -1061,7 +1061,7 @@ impl InsertQuery { let next_mac_subquery = NextMacAddress::new(interface.subnet.vpc_id, interface.kind); let next_ipv4_address_subquery = NextIpv4Address::new( - interface.subnet.ipv4_block.0 .0, + interface.subnet.ipv4_block.0.into(), interface.subnet.identity.id, ); let next_slot_subquery = NextNicSlot::new(interface.parent_id); @@ -1871,11 +1871,11 @@ mod tests { use omicron_common::api::external::Error; use omicron_common::api::external::IdentityMetadataCreateParams; use omicron_common::api::external::InstanceCpuCount; - use omicron_common::api::external::Ipv4Net; - use omicron_common::api::external::Ipv6Net; use omicron_common::api::external::MacAddr; use omicron_test_utils::dev; use omicron_test_utils::dev::db::CockroachInstance; + use oxnet::Ipv4Net; + use oxnet::Ipv6Net; use std::collections::HashSet; use std::convert::TryInto; use std::net::IpAddr; diff --git a/nexus/db-queries/src/db/queries/vpc_subnet.rs b/nexus/db-queries/src/db/queries/vpc_subnet.rs index 9ddec32080..fcd2e584fd 100644 --- a/nexus/db-queries/src/db/queries/vpc_subnet.rs +++ b/nexus/db-queries/src/db/queries/vpc_subnet.rs @@ -43,7 +43,9 @@ impl SubnetError { DatabaseErrorKind::NotNullViolation, ref info, ) if info.message() == IPV4_OVERLAP_ERROR_MESSAGE => { - SubnetError::OverlappingIpRange(subnet.ipv4_block.0 .0.into()) + SubnetError::OverlappingIpRange(ipnetwork::IpNetwork::V4( + subnet.ipv4_block.0.into(), + )) } // Attempt to insert overlapping IPv6 subnet @@ -51,7 +53,9 @@ impl SubnetError { DatabaseErrorKind::NotNullViolation, ref info, ) if info.message() == IPV6_OVERLAP_ERROR_MESSAGE => { - SubnetError::OverlappingIpRange(subnet.ipv6_block.0 .0.into()) + SubnetError::OverlappingIpRange(ipnetwork::IpNetwork::V6( + subnet.ipv6_block.0.into(), + )) } // Conflicting name for the subnet within a VPC @@ -233,8 +237,10 @@ pub struct FilterConflictingVpcSubnetRangesQuery { impl FilterConflictingVpcSubnetRangesQuery { pub fn new(subnet: VpcSubnet) -> Self { - let ipv4_block = ipnetwork::IpNetwork::from(subnet.ipv4_block.0 .0); - let ipv6_block = ipnetwork::IpNetwork::from(subnet.ipv6_block.0 .0); + let ipv4_block = + ipnetwork::Ipv4Network::from(subnet.ipv4_block.0).into(); + let ipv6_block = + ipnetwork::Ipv6Network::from(subnet.ipv6_block.0).into(); Self { subnet, ipv4_block, ipv6_block } } } @@ -394,10 +400,10 @@ mod test { use ipnetwork::IpNetwork; use nexus_test_utils::db::test_setup_database; use omicron_common::api::external::IdentityMetadataCreateParams; - use omicron_common::api::external::Ipv4Net; - use omicron_common::api::external::Ipv6Net; use omicron_common::api::external::Name; use omicron_test_utils::dev; + use oxnet::Ipv4Net; + use oxnet::Ipv6Net; use std::convert::TryInto; use std::sync::Arc; use uuid::Uuid; diff --git a/nexus/defaults/Cargo.toml b/nexus/defaults/Cargo.toml index 535b78054b..b3e8bbd6f9 100644 --- a/nexus/defaults/Cargo.toml +++ b/nexus/defaults/Cargo.toml @@ -7,6 +7,7 @@ license = "MPL-2.0" [dependencies] ipnetwork.workspace = true once_cell.workspace = true +oxnet.workspace = true rand.workspace = true serde_json.workspace = true diff --git a/nexus/defaults/src/lib.rs b/nexus/defaults/src/lib.rs index dd08b4e4ab..f99cf50486 100644 --- a/nexus/defaults/src/lib.rs +++ b/nexus/defaults/src/lib.rs @@ -4,12 +4,10 @@ //! Default values for data in the Nexus API, when not provided explicitly in a request. -use ipnetwork::Ipv4Network; -use ipnetwork::Ipv6Network; use omicron_common::api::external; -use omicron_common::api::external::Ipv4Net; -use omicron_common::api::external::Ipv6Net; use once_cell::sync::Lazy; +use oxnet::Ipv4Net; +use oxnet::Ipv6Net; use std::net::Ipv4Addr; use std::net::Ipv6Addr; @@ -20,10 +18,8 @@ pub const DEFAULT_PRIMARY_NIC_NAME: &str = "net0"; /// The default IPv4 subnet range assigned to the default VPC Subnet, when /// the VPC is created, if one is not provided in the request. See /// for details. -pub static DEFAULT_VPC_SUBNET_IPV4_BLOCK: Lazy = - Lazy::new(|| { - Ipv4Net(Ipv4Network::new(Ipv4Addr::new(172, 30, 0, 0), 22).unwrap()) - }); +pub static DEFAULT_VPC_SUBNET_IPV4_BLOCK: Lazy = + Lazy::new(|| Ipv4Net::new(Ipv4Addr::new(172, 30, 0, 0), 22).unwrap()); pub static DEFAULT_FIREWALL_RULES: Lazy = Lazy::new(|| { @@ -73,17 +69,17 @@ pub fn random_vpc_ipv6_prefix() -> Result { "Unable to allocate random IPv6 address range", ) })?; - Ok(Ipv6Net( - Ipv6Network::new( - Ipv6Addr::from(bytes), - Ipv6Net::VPC_IPV6_PREFIX_LENGTH, - ) - .unwrap(), - )) + Ok(Ipv6Net::new( + Ipv6Addr::from(bytes), + omicron_common::address::VPC_IPV6_PREFIX_LENGTH, + ) + .unwrap()) } #[cfg(test)] mod tests { + use omicron_common::api::external::Ipv6NetExt; + use super::*; #[test] diff --git a/nexus/networking/Cargo.toml b/nexus/networking/Cargo.toml index 11f6d83993..693fd743cb 100644 --- a/nexus/networking/Cargo.toml +++ b/nexus/networking/Cargo.toml @@ -9,6 +9,7 @@ futures.workspace = true ipnetwork.workspace = true nexus-db-queries.workspace = true omicron-common.workspace = true +oxnet.workspace = true reqwest.workspace = true sled-agent-client.workspace = true slog.workspace = true diff --git a/nexus/networking/src/firewall_rules.rs b/nexus/networking/src/firewall_rules.rs index dc67ce5937..484c1481e8 100644 --- a/nexus/networking/src/firewall_rules.rs +++ b/nexus/networking/src/firewall_rules.rs @@ -19,10 +19,10 @@ use nexus_db_queries::db::DataStore; use omicron_common::api::external; use omicron_common::api::external::AllowedSourceIps; use omicron_common::api::external::Error; -use omicron_common::api::external::IpNet; use omicron_common::api::external::ListResultVec; use omicron_common::api::internal::nexus::HostIdentifier; use omicron_common::api::internal::shared::NetworkInterface; +use oxnet::IpNet; use slog::debug; use slog::error; use slog::info; @@ -353,7 +353,7 @@ pub async fn resolve_firewall_rules_for_sled_agent( .unwrap_or(&no_interfaces) { host_addrs.push( - HostIdentifier::Ip(IpNet::from( + HostIdentifier::Ip(IpNet::host_net( interface.ip, )) .into(), @@ -373,7 +373,8 @@ pub async fn resolve_firewall_rules_for_sled_agent( } external::VpcFirewallRuleHostFilter::Ip(addr) => { host_addrs.push( - HostIdentifier::Ip(IpNet::from(*addr)).into(), + HostIdentifier::Ip(IpNet::host_net(*addr)) + .into(), ) } external::VpcFirewallRuleHostFilter::IpNet(net) => { diff --git a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs index 0ab61a50f4..a560c504c7 100644 --- a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs +++ b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs @@ -313,14 +313,12 @@ impl<'a> BlueprintBuilder<'a> { // of used resources we built above if needed. let nexus_v4_ips = AvailableIterator::new( NEXUS_OPTE_IPV4_SUBNET - .0 .iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), existing_nexus_v4_ips, ); let nexus_v6_ips = AvailableIterator::new( NEXUS_OPTE_IPV6_SUBNET - .0 .iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), existing_nexus_v6_ips, diff --git a/wicket/src/ui/panes/rack_setup.rs b/wicket/src/ui/panes/rack_setup.rs index f74baa3f2c..941f5f7dc1 100644 --- a/wicket/src/ui/panes/rack_setup.rs +++ b/wicket/src/ui/panes/rack_setup.rs @@ -1093,8 +1093,8 @@ fn rss_config_text<'a>( Some(AllowedSourceIps::List(list)) => list .iter() .map(|net| { - let as_str = if net.first_address() == net.last_address() { - net.ip().to_string() + let as_str = if net.is_host_net() { + net.addr().to_string() } else { net.to_string() }; diff --git a/wicketd/src/rss_config.rs b/wicketd/src/rss_config.rs index 0160aa7c77..dbd166f9da 100644 --- a/wicketd/src/rss_config.rs +++ b/wicketd/src/rss_config.rs @@ -651,7 +651,7 @@ fn validate_rack_network_config( // TODO Add more client side checks on `rack_network_config` contents? Ok(bootstrap_agent_client::types::RackNetworkConfigV1 { - rack_subnet: RACK_SUBNET.net(), + rack_subnet: RACK_SUBNET.net().into(), infra_ip_first: config.infra_ip_first, infra_ip_last: config.infra_ip_last, ports: config From fdd86e2ecf830d43e8b5667f1c9d1e7232425b87 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 8 May 2024 14:50:15 -0700 Subject: [PATCH 04/23] all building --- Cargo.lock | 2 + clients/sled-agent-client/src/lib.rs | 7 + common/src/api/external/mod.rs | 583 +++--------------- nexus/Cargo.toml | 1 + .../src/db/datastore/ipv4_nat_entry.rs | 47 +- nexus/db-queries/src/db/datastore/mod.rs | 4 +- .../src/db/datastore/network_interface.rs | 1 - nexus/db-queries/src/db/datastore/rack.rs | 50 +- nexus/db-queries/src/db/datastore/vpc.rs | 2 +- .../src/db/queries/network_interface.rs | 26 +- nexus/db-queries/src/db/queries/vpc_subnet.rs | 14 +- nexus/networking/src/firewall_rules.rs | 4 +- nexus/reconfigurator/execution/Cargo.toml | 1 + .../execution/src/external_networking.rs | 2 +- nexus/src/app/allow_list.rs | 2 +- .../app/background/sync_service_zone_nat.rs | 16 +- nexus/src/app/bgp.rs | 9 +- nexus/src/app/instance_network.rs | 12 +- nexus/src/app/sagas/vpc_create.rs | 16 +- nexus/src/app/switch_interface.rs | 3 +- nexus/src/app/vpc_subnet.rs | 13 +- nexus/src/context.rs | 3 +- nexus/tests/integration_tests/endpoints.rs | 3 +- nexus/tests/integration_tests/instances.rs | 8 +- .../integration_tests/subnet_allocation.rs | 7 +- nexus/tests/integration_tests/vpc_subnets.rs | 21 +- nexus/tests/integration_tests/vpcs.rs | 3 +- 27 files changed, 206 insertions(+), 654 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9d4bdf172..7334543ace 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4771,6 +4771,7 @@ dependencies = [ "omicron-test-utils", "omicron-uuid-kinds", "omicron-workspace-hack", + "oxnet", "pq-sys", "reqwest", "sled-agent-client", @@ -5442,6 +5443,7 @@ dependencies = [ "oximeter-db", "oximeter-instruments", "oximeter-producer", + "oxnet", "parse-display", "paste", "pem", diff --git a/clients/sled-agent-client/src/lib.rs b/clients/sled-agent-client/src/lib.rs index 6c74411c46..d45a557ea0 100644 --- a/clients/sled-agent-client/src/lib.rs +++ b/clients/sled-agent-client/src/lib.rs @@ -46,6 +46,7 @@ progenitor::generate_api!( Name = omicron_common::api::external::Name, SwitchLocation = omicron_common::api::external::SwitchLocation, ImportExportPolicy = omicron_common::api::external::ImportExportPolicy, + Ipv6Network = ipnetwork::Ipv6Network, IpNetwork = ipnetwork::IpNetwork, PortFec = omicron_common::api::internal::shared::PortFec, PortSpeed = omicron_common::api::internal::shared::PortSpeed, @@ -438,6 +439,12 @@ impl From for types::Ipv4Net { } } +impl From for types::Ipv4Network { + fn from(n: ipnetwork::Ipv4Network) -> Self { + Self::try_from(n.to_string()).unwrap_or_else(|e| panic!("{}: {}", n, e)) + } +} + impl From for oxnet::Ipv4Net { fn from(n: types::Ipv4Net) -> Self { n.parse().unwrap() diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index 07ca2d72f5..c7982b4433 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -22,6 +22,7 @@ use dropshot::HttpError; pub use dropshot::PaginationOrder; pub use error::*; use futures::stream::BoxStream; +use oxnet::IpNet; use parse_display::Display; use parse_display::FromStr; use rand::thread_rng; @@ -1220,412 +1221,35 @@ impl DiskState { } } -/// An `Ipv4Net` represents a IPv4 subnetwork, including the address and network mask. -#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Eq, Serialize)] -struct Ipv4Net(pub ipnetwork::Ipv4Network); - -impl Ipv4Net { - /// Return `true` if this IPv4 subnetwork is from an RFC 1918 private - /// address space. - pub fn is_private(&self) -> bool { - self.0.network().is_private() - } -} - -impl std::ops::Deref for Ipv4Net { - type Target = ipnetwork::Ipv4Network; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl std::fmt::Display for Ipv4Net { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl JsonSchema for Ipv4Net { - fn schema_name() -> String { - "Ipv4Net".to_string() - } - - fn json_schema( - _: &mut schemars::gen::SchemaGenerator, - ) -> schemars::schema::Schema { - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - title: Some("An IPv4 subnet".to_string()), - description: Some( - "An IPv4 subnet, including prefix and subnet mask" - .to_string(), - ), - examples: vec!["192.168.1.0/24".into()], - ..Default::default() - })), - instance_type: Some(schemars::schema::InstanceType::String.into()), - string: Some(Box::new(schemars::schema::StringValidation { - pattern: Some( - concat!( - r#"^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}"#, - r#"([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"#, - r#"/([0-9]|1[0-9]|2[0-9]|3[0-2])$"#, - ) - .to_string(), - ), - ..Default::default() - })), - ..Default::default() - } - .into() - } -} - -/// An `Ipv6Net` represents a IPv6 subnetwork, including the address and network mask. -#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Eq, Serialize)] -struct Ipv6Net(pub ipnetwork::Ipv6Network); - -impl Ipv6Net { +pub trait Ipv6NetExt { /// The length for all VPC IPv6 prefixes - pub const VPC_IPV6_PREFIX_LENGTH: u8 = 48; - - /// The prefix length for all VPC Sunets - pub const VPC_SUBNET_IPV6_PREFIX_LENGTH: u8 = 64; + const VPC_IPV6_PREFIX_LENGTH: u8 = 48; - /// Return `true` if this subnetwork is in the IPv6 Unique Local Address - /// range defined in RFC 4193, e.g., `fd00:/8` - pub fn is_unique_local(&self) -> bool { - // TODO: Delegate to `Ipv6Addr::is_unique_local()` when stabilized. - self.0.network().octets()[0] == 0xfd - } + /// The prefix length for all VPC Subnets + const VPC_SUBNET_IPV6_PREFIX_LENGTH: u8 = 64; /// Return `true` if this subnetwork is a valid VPC prefix. /// /// This checks that the subnet is a unique local address, and has the VPC /// prefix length required. - pub fn is_vpc_prefix(&self) -> bool { - self.is_unique_local() - && self.0.prefix() == Self::VPC_IPV6_PREFIX_LENGTH - } + fn is_vpc_prefix(&self) -> bool; /// Return `true` if this subnetwork is a valid VPC Subnet, given the VPC's /// prefix. - pub fn is_vpc_subnet(&self, vpc_prefix: &Ipv6Net) -> bool { - self.is_unique_local() - && self.is_subnet_of(vpc_prefix.0) - && self.prefix() == Self::VPC_SUBNET_IPV6_PREFIX_LENGTH - } -} - -pub trait Ipv6NetExt { - /// Return `true` if this subnetwork is a valid VPC prefix. - /// - /// This checks that the subnet is a unique local address, and has the VPC - /// prefix length required. - fn is_vpc_prefix(&self) -> bool; + fn is_vpc_subnet(&self, vpc_prefix: &Self) -> bool; } impl Ipv6NetExt for oxnet::Ipv6Net { fn is_vpc_prefix(&self) -> bool { - /// The length for all VPC IPv6 prefixes - pub const VPC_IPV6_PREFIX_LENGTH: u8 = 48; - // /// The prefix length for all VPC subnets // pub const VPC_SUBNET_IPV6_PREFIX_LENGTH: u8 = 64; - self.is_unique_local() && self.prefix() == VPC_IPV6_PREFIX_LENGTH + self.is_unique_local() && self.prefix() == Self::VPC_IPV6_PREFIX_LENGTH } -} - -impl std::ops::Deref for Ipv6Net { - type Target = ipnetwork::Ipv6Network; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl std::fmt::Display for Ipv6Net { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl From for Ipv6Net { - fn from(n: ipnetwork::Ipv6Network) -> Ipv6Net { - Self(n) - } -} - -const IPV6_NET_REGEX: &str = concat!( - r#"^("#, - r#"([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|"#, - r#"([0-9a-fA-F]{1,4}:){1,7}:|"#, - r#"([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|"#, - r#"([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|"#, - r#"([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|"#, - r#"([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|"#, - r#"([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|"#, - r#"[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|"#, - r#":((:[0-9a-fA-F]{1,4}){1,7}|:)|"#, - r#"fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|"#, - r#"::(ffff(:0{1,4}){0,1}:){0,1}"#, - r#"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}"#, - r#"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|"#, - r#"([0-9a-fA-F]{1,4}:){1,4}:"#, - r#"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}"#, - r#"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"#, - r#")\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$"#, -); - -#[cfg(test)] -#[test] -fn test_ipv6_regex() { - let re = regress::Regex::new(IPV6_NET_REGEX).unwrap(); - for case in [ - "1:2:3:4:5:6:7:8", - "1:a:2:b:3:c:4:d", - "1::", - "::1", - "::", - "1::3:4:5:6:7:8", - "1:2::4:5:6:7:8", - "1:2:3::5:6:7:8", - "1:2:3:4::6:7:8", - "1:2:3:4:5::7:8", - "1:2:3:4:5:6::8", - "1:2:3:4:5:6:7::", - "2001::", - "fd00::", - "::100:1", - "fd12:3456::", - ] { - for prefix in 0..=128 { - let net = format!("{case}/{prefix}"); - assert!( - re.find(&net).is_some(), - "Expected to match IPv6 case: {}", - prefix, - ); - } - } -} - -impl JsonSchema for Ipv6Net { - fn schema_name() -> String { - "Ipv6Net".to_string() - } - - fn json_schema( - _: &mut schemars::gen::SchemaGenerator, - ) -> schemars::schema::Schema { - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - title: Some("An IPv6 subnet".to_string()), - description: Some( - "An IPv6 subnet, including prefix and subnet mask" - .to_string(), - ), - examples: vec!["fd12:3456::/64".into()], - ..Default::default() - })), - instance_type: Some(schemars::schema::InstanceType::String.into()), - string: Some(Box::new(schemars::schema::StringValidation { - pattern: Some(IPV6_NET_REGEX.to_string()), - ..Default::default() - })), - ..Default::default() - } - .into() - } -} -/// An `IpNet` represents an IP network, either IPv4 or IPv6. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -enum IpNet { - V4(Ipv4Net), - V6(Ipv6Net), -} - -impl IpNet { - /// Return the underlying address. - pub fn ip(&self) -> IpAddr { - match self { - IpNet::V4(inner) => inner.ip().into(), - IpNet::V6(inner) => inner.ip().into(), - } - } - - /// Return the underlying prefix length. - pub fn prefix(&self) -> u8 { - match self { - IpNet::V4(inner) => inner.prefix(), - IpNet::V6(inner) => inner.prefix(), - } - } - - /// Return the first address in this subnet - pub fn first_address(&self) -> IpAddr { - match self { - IpNet::V4(inner) => IpAddr::from(inner.iter().next().unwrap()), - IpNet::V6(inner) => IpAddr::from(inner.iter().next().unwrap()), - } - } - - /// Return the last address in this subnet. - /// - /// For a subnet of size 1, e.g., a /32, this is the same as the first - /// address. - // NOTE: This is a workaround for the fact that the `ipnetwork` crate's - // iterator provides only the `Iterator::next()` method. That means that - // finding the last address is linear in the size of the subnet, which is - // completely untenable and totally avoidable with some addition. In the - // long term, we should either put up a patch to the `ipnetwork` crate or - // move the `ipnet` crate, which does provide an efficient iterator - // implementation. - pub fn last_address(&self) -> IpAddr { - match self { - IpNet::V4(inner) => { - let base: u32 = inner.network().into(); - let size = inner.size() - 1; - std::net::IpAddr::V4(std::net::Ipv4Addr::from(base + size)) - } - IpNet::V6(inner) => { - let base: u128 = inner.network().into(); - let size = inner.size() - 1; - std::net::IpAddr::V6(std::net::Ipv6Addr::from(base + size)) - } - } - } - - /// Return true if the provided address is contained in self. - /// - /// This returns false if the address and the network are of different IP - /// families. - pub fn contains(&self, addr: IpAddr) -> bool { - match (self, addr) { - (IpNet::V4(net), IpAddr::V4(ip)) => net.contains(ip), - (IpNet::V6(net), IpAddr::V6(ip)) => net.contains(ip), - (_, _) => false, - } - } -} - -impl From for IpNet { - fn from(n: ipnetwork::IpNetwork) -> Self { - match n { - ipnetwork::IpNetwork::V4(v4) => IpNet::V4(Ipv4Net(v4)), - ipnetwork::IpNetwork::V6(v6) => IpNet::V6(Ipv6Net(v6)), - } - } -} - -impl From for IpNet { - fn from(n: Ipv4Net) -> IpNet { - IpNet::V4(n) - } -} - -impl From for IpNet { - fn from(n: Ipv4Addr) -> IpNet { - IpNet::V4(Ipv4Net(ipnetwork::Ipv4Network::from(n))) - } -} - -impl From for IpNet { - fn from(n: Ipv6Net) -> IpNet { - IpNet::V6(n) - } -} - -impl From for IpNet { - fn from(n: Ipv6Addr) -> IpNet { - IpNet::V6(Ipv6Net(ipnetwork::Ipv6Network::from(n))) - } -} - -impl From for IpNet { - fn from(n: IpAddr) -> IpNet { - match n { - IpAddr::V4(v4) => IpNet::from(v4), - IpAddr::V6(v6) => IpNet::from(v6), - } - } -} - -impl std::fmt::Display for IpNet { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - IpNet::V4(inner) => write!(f, "{}", inner), - IpNet::V6(inner) => write!(f, "{}", inner), - } - } -} - -impl FromStr for IpNet { - type Err = String; - - fn from_str(s: &str) -> Result { - let net = - s.parse::().map_err(|e| e.to_string())?; - match net { - ipnetwork::IpNetwork::V4(net) => Ok(IpNet::from(Ipv4Net(net))), - ipnetwork::IpNetwork::V6(net) => Ok(IpNet::from(Ipv6Net(net))), - } - } -} - -impl From for ipnetwork::IpNetwork { - fn from(net: IpNet) -> ipnetwork::IpNetwork { - match net { - IpNet::V4(net) => ipnetwork::IpNetwork::from(net.0), - IpNet::V6(net) => ipnetwork::IpNetwork::from(net.0), - } - } -} - -impl Serialize for IpNet { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self { - IpNet::V4(v4) => v4.serialize(serializer), - IpNet::V6(v6) => v6.serialize(serializer), - } - } -} - -impl<'de> Deserialize<'de> for IpNet { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let net = ipnetwork::IpNetwork::deserialize(deserializer)?; - match net { - ipnetwork::IpNetwork::V4(net) => Ok(IpNet::from(Ipv4Net(net))), - ipnetwork::IpNetwork::V6(net) => Ok(IpNet::from(Ipv6Net(net))), - } - } -} - -impl JsonSchema for IpNet { - fn schema_name() -> String { - "IpNet".to_string() - } - - fn json_schema( - gen: &mut schemars::gen::SchemaGenerator, - ) -> schemars::schema::Schema { - schemars::schema::SchemaObject { - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - one_of: Some(vec![ - label_schema("v4", gen.subschema_for::()), - label_schema("v6", gen.subschema_for::()), - ]), - ..Default::default() - })), - ..Default::default() - } - .into() + fn is_vpc_subnet(&self, vpc_prefix: &Self) -> bool { + self.is_unique_local() + && self.is_subnet_of(vpc_prefix) + && self.prefix() == Self::VPC_SUBNET_IPV6_PREFIX_LENGTH } } @@ -3226,7 +2850,6 @@ mod test { use serde::Deserialize; use serde::Serialize; - use super::IpNet; use super::RouteDestination; use super::RouteTarget; use super::SemverVersion; @@ -3682,31 +3305,29 @@ mod test { #[test] fn test_ipv6_net_operations() { - use super::Ipv6Net; - assert!(Ipv6Net("fd00::/8".parse().unwrap()).is_unique_local()); - assert!(!Ipv6Net("fe00::/8".parse().unwrap()).is_unique_local()); - - assert!(Ipv6Net("fd00::/48".parse().unwrap()).is_vpc_prefix()); - assert!(!Ipv6Net("fe00::/48".parse().unwrap()).is_vpc_prefix()); - assert!(!Ipv6Net("fd00::/40".parse().unwrap()).is_vpc_prefix()); - - let vpc_prefix = Ipv6Net("fd00::/48".parse().unwrap()); - assert!( - Ipv6Net("fd00::/64".parse().unwrap()).is_vpc_subnet(&vpc_prefix) - ); - assert!( - !Ipv6Net("fd10::/64".parse().unwrap()).is_vpc_subnet(&vpc_prefix) - ); - assert!( - !Ipv6Net("fd00::/63".parse().unwrap()).is_vpc_subnet(&vpc_prefix) - ); - } - - #[test] - fn test_ipv4_net_operations() { - use super::{IpNet, Ipv4Net}; - let x: IpNet = "0.0.0.0/0".parse().unwrap(); - assert_eq!(x, IpNet::V4(Ipv4Net("0.0.0.0/0".parse().unwrap()))) + use super::Ipv6NetExt; + use oxnet::Ipv6Net; + + assert!("fd00::/8".parse::().unwrap().is_unique_local()); + assert!(!"fe00::/8".parse::().unwrap().is_unique_local()); + + assert!("fd00::/48".parse::().unwrap().is_vpc_prefix()); + assert!(!"fe00::/48".parse::().unwrap().is_vpc_prefix()); + assert!(!"fd00::/40".parse::().unwrap().is_vpc_prefix()); + + let vpc_prefix = "fd00::/48".parse::().unwrap(); + assert!("fd00::/64" + .parse::() + .unwrap() + .is_vpc_subnet(&vpc_prefix)); + assert!(!"fd10::/64" + .parse::() + .unwrap() + .is_vpc_subnet(&vpc_prefix)); + assert!(!"fd00::/63" + .parse::() + .unwrap() + .is_vpc_subnet(&vpc_prefix)); } #[test] @@ -3837,91 +3458,55 @@ mod test { assert!("hash:super_random".parse::().is_err()); } - #[test] - fn test_ipnet_serde() { - //TODO: none of this actually exercises - // schemars::schema::StringValidation bits and the schemars - // documentation is not forthcoming on how this might be accomplished. - let net_str = "fd00:2::/32"; - let net = IpNet::from_str(net_str).unwrap(); - let ser = serde_json::to_string(&net).unwrap(); - - assert_eq!(format!(r#""{}""#, net_str), ser); - let net_des = serde_json::from_str::(&ser).unwrap(); - assert_eq!(net, net_des); - - let net_str = "fd00:47::1/64"; - let net = IpNet::from_str(net_str).unwrap(); - let ser = serde_json::to_string(&net).unwrap(); - - assert_eq!(format!(r#""{}""#, net_str), ser); - let net_des = serde_json::from_str::(&ser).unwrap(); - assert_eq!(net, net_des); - - let net_str = "192.168.1.1/16"; - let net = IpNet::from_str(net_str).unwrap(); - let ser = serde_json::to_string(&net).unwrap(); - - assert_eq!(format!(r#""{}""#, net_str), ser); - let net_des = serde_json::from_str::(&ser).unwrap(); - assert_eq!(net, net_des); - - let net_str = "0.0.0.0/0"; - let net = IpNet::from_str(net_str).unwrap(); - let ser = serde_json::to_string(&net).unwrap(); - - assert_eq!(format!(r#""{}""#, net_str), ser); - let net_des = serde_json::from_str::(&ser).unwrap(); - assert_eq!(net, net_des); - } - - #[test] - fn test_ipnet_first_last_address() { - use std::net::IpAddr; - use std::net::Ipv4Addr; - use std::net::Ipv6Addr; - let net: IpNet = "fd00::/128".parse().unwrap(); - assert_eq!( - net.first_address(), - IpAddr::from(Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 0)), - ); - assert_eq!( - net.last_address(), - IpAddr::from(Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 0)), - ); - - let net: IpNet = "fd00::/64".parse().unwrap(); - assert_eq!( - net.first_address(), - IpAddr::from(Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 0)), - ); - assert_eq!( - net.last_address(), - IpAddr::from(Ipv6Addr::new( - 0xfd00, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff - )), - ); - - let net: IpNet = "10.0.0.0/16".parse().unwrap(); - assert_eq!( - net.first_address(), - IpAddr::from(Ipv4Addr::new(10, 0, 0, 0)), - ); - assert_eq!( - net.last_address(), - IpAddr::from(Ipv4Addr::new(10, 0, 255, 255)), - ); - - let net: IpNet = "10.0.0.0/32".parse().unwrap(); - assert_eq!( - net.first_address(), - IpAddr::from(Ipv4Addr::new(10, 0, 0, 0)), - ); - assert_eq!( - net.last_address(), - IpAddr::from(Ipv4Addr::new(10, 0, 0, 0)), - ); - } + // #[test] + // fn test_ipnet_first_last_address() { + // use oxnet::IpNet; + // use std::net::IpAddr; + // use std::net::Ipv4Addr; + // use std::net::Ipv6Addr; + + // let net: IpNet = "fd00::/128".parse().unwrap(); + // assert_eq!( + // net.first_address(), + // IpAddr::from(Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 0)), + // ); + // assert_eq!( + // net.last_address(), + // IpAddr::from(Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 0)), + // ); + + // let net: IpNet = "fd00::/64".parse().unwrap(); + // assert_eq!( + // net.first_address(), + // IpAddr::from(Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 0)), + // ); + // assert_eq!( + // net.last_address(), + // IpAddr::from(Ipv6Addr::new( + // 0xfd00, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff + // )), + // ); + + // let net: IpNet = "10.0.0.0/16".parse().unwrap(); + // assert_eq!( + // net.first_address(), + // IpAddr::from(Ipv4Addr::new(10, 0, 0, 0)), + // ); + // assert_eq!( + // net.last_address(), + // IpAddr::from(Ipv4Addr::new(10, 0, 255, 255)), + // ); + + // let net: IpNet = "10.0.0.0/32".parse().unwrap(); + // assert_eq!( + // net.first_address(), + // IpAddr::from(Ipv4Addr::new(10, 0, 0, 0)), + // ); + // assert_eq!( + // net.last_address(), + // IpAddr::from(Ipv4Addr::new(10, 0, 0, 0)), + // ); + // } #[test] fn test_macaddr() { diff --git a/nexus/Cargo.toml b/nexus/Cargo.toml index 5222d104c3..cad95f1614 100644 --- a/nexus/Cargo.toml +++ b/nexus/Cargo.toml @@ -47,6 +47,7 @@ once_cell.workspace = true openssl.workspace = true oximeter-client.workspace = true oximeter-db.workspace = true +oxnet.workspace = true parse-display.workspace = true paste.workspace = true # See omicron-rpaths for more about the "pq-sys" dependency. diff --git a/nexus/db-queries/src/db/datastore/ipv4_nat_entry.rs b/nexus/db-queries/src/db/datastore/ipv4_nat_entry.rs index fa3939b8ac..5b370f27a9 100644 --- a/nexus/db-queries/src/db/datastore/ipv4_nat_entry.rs +++ b/nexus/db-queries/src/db/datastore/ipv4_nat_entry.rs @@ -406,13 +406,11 @@ mod test { // Each change (creation / deletion) to the NAT table should increment the // version number of the row in the NAT table - let external_address = external::Ipv4Net( - ipnetwork::Ipv4Network::try_from("10.0.0.100").unwrap(), - ); + let external_address = + oxnet::Ipv4Net::host_net("10.0.0.100".parse().unwrap()); - let sled_address = external::Ipv6Net( - ipnetwork::Ipv6Network::try_from("fd00:1122:3344:104::1").unwrap(), - ); + let sled_address = + oxnet::Ipv6Net::host_net("fd00:1122:3344:104::1".parse().unwrap()); // Add a nat entry. let nat1 = Ipv4NatValues { @@ -565,13 +563,11 @@ mod test { // Each change (creation / deletion) to the NAT table should increment the // version number of the row in the NAT table - let external_address = external::Ipv4Net( - ipnetwork::Ipv4Network::try_from("10.0.0.100").unwrap(), - ); + let external_address = + oxnet::Ipv4Net::host_net("10.0.0.100".parse().unwrap()); - let sled_address = external::Ipv6Net( - ipnetwork::Ipv6Network::try_from("fd00:1122:3344:104::1").unwrap(), - ); + let sled_address = + oxnet::Ipv6Net::host_net("fd00:1122:3344:104::1".parse().unwrap()); // Add a nat entry. let nat1 = Ipv4NatValues { @@ -711,13 +707,11 @@ mod test { // 1. an entry should be deleted during the next sync // 2. an entry that should be kept during the next sync - let external_address = external::Ipv4Net( - ipnetwork::Ipv4Network::try_from("10.0.0.100").unwrap(), - ); + let external_address = + oxnet::Ipv4Net::host_net("10.0.0.100".parse().unwrap()); - let sled_address = external::Ipv6Net( - ipnetwork::Ipv6Network::try_from("fd00:1122:3344:104::1").unwrap(), - ); + let sled_address = + oxnet::Ipv6Net::host_net("fd00:1122:3344:104::1".parse().unwrap()); // Add a nat entry. let nat1 = Ipv4NatValues { @@ -833,13 +827,12 @@ mod test { let addresses = (0..=255).map(|i| { let addr = Ipv4Addr::new(10, 0, 0, i); - let net = ipnetwork::Ipv4Network::new(addr, 32).unwrap(); - external::Ipv4Net(net) + let net = oxnet::Ipv4Net::new(addr, 32).unwrap(); + net }); - let sled_address = external::Ipv6Net( - ipnetwork::Ipv6Network::try_from("fd00:1122:3344:104::1").unwrap(), - ); + let sled_address = + oxnet::Ipv6Net::host_net("fd00:1122:3344:104::1".parse().unwrap()); let nat_entries = addresses.map(|external_address| { // build a bunch of nat entries @@ -908,7 +901,7 @@ mod test { .expect("did not find a deleted nat entry with a matching version number"); assert_eq!( - deleted_nat.external_address.ip(), + deleted_nat.external_address.addr(), change.external_address ); assert_eq!( @@ -917,7 +910,7 @@ mod test { ); assert_eq!(deleted_nat.last_port, change.last_port.into()); assert_eq!( - deleted_nat.sled_address.ip(), + deleted_nat.sled_address.addr(), change.sled_address ); assert_eq!(*deleted_nat.mac, change.mac); @@ -933,13 +926,13 @@ mod test { assert!(added_nat.version_removed.is_none()); assert_eq!( - added_nat.external_address.ip(), + added_nat.external_address.addr(), change.external_address ); assert_eq!(added_nat.first_port, change.first_port.into()); assert_eq!(added_nat.last_port, change.last_port.into()); assert_eq!( - added_nat.sled_address.ip(), + added_nat.sled_address.addr(), change.sled_address ); assert_eq!(*added_nat.mac, change.mac); diff --git a/nexus/db-queries/src/db/datastore/mod.rs b/nexus/db-queries/src/db/datastore/mod.rs index 9ade7200d4..0f2cae7331 100644 --- a/nexus/db-queries/src/db/datastore/mod.rs +++ b/nexus/db-queries/src/db/datastore/mod.rs @@ -1587,8 +1587,8 @@ mod test { name: external::Name::try_from(String::from("name")).unwrap(), description: String::from("description"), }, - external::Ipv4Net("172.30.0.0/22".parse().unwrap()), - external::Ipv6Net("fd00::/64".parse().unwrap()), + "172.30.0.0/22".parse().unwrap(), + "fd00::/64".parse().unwrap(), ); let values = FilterConflictingVpcSubnetRangesQuery::new(subnet); let query = diff --git a/nexus/db-queries/src/db/datastore/network_interface.rs b/nexus/db-queries/src/db/datastore/network_interface.rs index d7ef346cbd..abaeab87cf 100644 --- a/nexus/db-queries/src/db/datastore/network_interface.rs +++ b/nexus/db-queries/src/db/datastore/network_interface.rs @@ -838,7 +838,6 @@ mod tests { // Insert 10 Nexus NICs let ip_range = NEXUS_OPTE_IPV4_SUBNET - .0 .iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES) .take(10); diff --git a/nexus/db-queries/src/db/datastore/rack.rs b/nexus/db-queries/src/db/datastore/rack.rs index a072d65147..aceb2b2135 100644 --- a/nexus/db-queries/src/db/datastore/rack.rs +++ b/nexus/db-queries/src/db/datastore/rack.rs @@ -1000,6 +1000,7 @@ mod test { use omicron_uuid_kinds::{ExternalIpUuid, OmicronZoneUuid}; use omicron_uuid_kinds::{GenericUuid, ZpoolUuid}; use omicron_uuid_kinds::{SledUuid, TypedUuid}; + use oxnet::IpNet; use sled_agent_client::types::OmicronZoneDataset; use std::collections::{BTreeMap, HashMap}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV6}; @@ -1337,10 +1338,8 @@ mod test { name: "external-dns".parse().unwrap(), ip: external_dns_pip.into(), mac: macs.next().unwrap(), - subnet: IpNetwork::from( - **DNS_OPTE_IPV4_SUBNET, - ) - .into(), + subnet: IpNet::from(*DNS_OPTE_IPV4_SUBNET) + .into(), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -1366,10 +1365,8 @@ mod test { name: "ntp1".parse().unwrap(), ip: ntp1_pip.into(), mac: macs.next().unwrap(), - subnet: IpNetwork::from( - **NTP_OPTE_IPV4_SUBNET, - ) - .into(), + subnet: IpNet::from(*NTP_OPTE_IPV4_SUBNET) + .into(), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -1413,8 +1410,8 @@ mod test { name: "nexus".parse().unwrap(), ip: nexus_pip.into(), mac: macs.next().unwrap(), - subnet: IpNetwork::from( - **NEXUS_OPTE_IPV4_SUBNET, + subnet: IpNet::from( + *NEXUS_OPTE_IPV4_SUBNET, ) .into(), vni: Vni::SERVICES_VNI, @@ -1442,10 +1439,8 @@ mod test { name: "ntp2".parse().unwrap(), ip: ntp2_pip.into(), mac: macs.next().unwrap(), - subnet: IpNetwork::from( - **NTP_OPTE_IPV4_SUBNET, - ) - .into(), + subnet: IpNet::from(*NTP_OPTE_IPV4_SUBNET) + .into(), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -1666,8 +1661,8 @@ mod test { name: "nexus1".parse().unwrap(), ip: nexus_pip1.into(), mac: macs.next().unwrap(), - subnet: IpNetwork::from( - **NEXUS_OPTE_IPV4_SUBNET, + subnet: IpNet::from( + *NEXUS_OPTE_IPV4_SUBNET, ) .into(), vni: Vni::SERVICES_VNI, @@ -1698,10 +1693,9 @@ mod test { name: "nexus2".parse().unwrap(), ip: nexus_pip2.into(), mac: macs.next().unwrap(), - subnet: IpNetwork::from( - **NEXUS_OPTE_IPV4_SUBNET, - ) - .into(), + subnet: oxnet::IpNet::from( + *NEXUS_OPTE_IPV4_SUBNET, + ), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -1935,10 +1929,8 @@ mod test { name: "nexus".parse().unwrap(), ip: nexus_pip.into(), mac: macs.next().unwrap(), - subnet: IpNetwork::from( - **NEXUS_OPTE_IPV4_SUBNET, - ) - .into(), + subnet: IpNet::from(*NEXUS_OPTE_IPV4_SUBNET) + .into(), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -2039,10 +2031,8 @@ mod test { name: "external-dns".parse().unwrap(), ip: external_dns_pip.into(), mac: macs.next().unwrap(), - subnet: IpNetwork::from( - **DNS_OPTE_IPV4_SUBNET, - ) - .into(), + subnet: IpNet::from(*DNS_OPTE_IPV4_SUBNET) + .into(), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -2071,8 +2061,8 @@ mod test { name: "nexus".parse().unwrap(), ip: nexus_pip.into(), mac: macs.next().unwrap(), - subnet: IpNetwork::from( - **NEXUS_OPTE_IPV4_SUBNET, + subnet: IpNet::from( + *NEXUS_OPTE_IPV4_SUBNET, ) .into(), vni: Vni::SERVICES_VNI, diff --git a/nexus/db-queries/src/db/datastore/vpc.rs b/nexus/db-queries/src/db/datastore/vpc.rs index 34c18d39a4..7fe0d8420f 100644 --- a/nexus/db-queries/src/db/datastore/vpc.rs +++ b/nexus/db-queries/src/db/datastore/vpc.rs @@ -1249,7 +1249,6 @@ mod tests { use omicron_common::address::NEXUS_OPTE_IPV4_SUBNET; use omicron_common::api::external; use omicron_common::api::external::Generation; - use omicron_common::api::external::IpNet; use omicron_common::api::external::MacAddr; use omicron_common::api::external::Vni; use omicron_common::api::internal::shared::NetworkInterface; @@ -1259,6 +1258,7 @@ mod tests { use omicron_uuid_kinds::GenericUuid; use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::SledUuid; + use oxnet::IpNet; use slog::info; use std::collections::BTreeMap; use std::net::IpAddr; diff --git a/nexus/db-queries/src/db/queries/network_interface.rs b/nexus/db-queries/src/db/queries/network_interface.rs index 02185183d0..bf0b1722b5 100644 --- a/nexus/db-queries/src/db/queries/network_interface.rs +++ b/nexus/db-queries/src/db/queries/network_interface.rs @@ -1995,25 +1995,13 @@ mod tests { let vpc_id = Uuid::new_v4(); let mut subnets = Vec::with_capacity(n_subnets as _); for i in 0..n_subnets { - let ipv4net = Ipv4Net( - Ipv4Network::new(Ipv4Addr::new(172, 30, 0, i), 28).unwrap(), - ); - let ipv6net = Ipv6Net( - Ipv6Network::new( - Ipv6Addr::new( - 0xfd12, - 0x3456, - 0x7890, - i.into(), - 0, - 0, - 0, - 0, - ), - 64, - ) - .unwrap(), - ); + let ipv4net = + Ipv4Net::new(Ipv4Addr::new(172, 30, 0, i), 28).unwrap(); + let ipv6net = Ipv6Net::new( + Ipv6Addr::new(0xfd12, 0x3456, 0x7890, i.into(), 0, 0, 0, 0), + 64, + ) + .unwrap(); let subnet = VpcSubnet::new( Uuid::new_v4(), vpc_id, diff --git a/nexus/db-queries/src/db/queries/vpc_subnet.rs b/nexus/db-queries/src/db/queries/vpc_subnet.rs index fcd2e584fd..72f2771a1e 100644 --- a/nexus/db-queries/src/db/queries/vpc_subnet.rs +++ b/nexus/db-queries/src/db/queries/vpc_subnet.rs @@ -402,8 +402,6 @@ mod test { use omicron_common::api::external::IdentityMetadataCreateParams; use omicron_common::api::external::Name; use omicron_test_utils::dev; - use oxnet::Ipv4Net; - use oxnet::Ipv6Net; use std::convert::TryInto; use std::sync::Arc; use uuid::Uuid; @@ -415,10 +413,10 @@ mod test { name: name.clone(), description: description.to_string(), }; - let ipv4_block = Ipv4Net("172.30.0.0/22".parse().unwrap()); - let other_ipv4_block = Ipv4Net("172.31.0.0/22".parse().unwrap()); - let ipv6_block = Ipv6Net("fd12:3456:7890::/64".parse().unwrap()); - let other_ipv6_block = Ipv6Net("fd00::/64".parse().unwrap()); + let ipv4_block = "172.30.0.0/22".parse().unwrap(); + let other_ipv4_block = "172.31.0.0/22".parse().unwrap(); + let ipv6_block = "fd12:3456:7890::/64".parse().unwrap(); + let other_ipv6_block = "fd00::/64".parse().unwrap(); let name = "a-name".to_string().try_into().unwrap(); let other_name = "b-name".to_string().try_into().unwrap(); let description = "some description".to_string(); @@ -497,7 +495,7 @@ mod test { .expect_err("Should not be able to insert VPC Subnet with overlapping IPv6 range"); assert_eq!( err, - SubnetError::OverlappingIpRange(IpNetwork::from(ipv6_block.0)), + SubnetError::OverlappingIpRange(ipnetwork::IpNetwork::from(oxnet::IpNet::from(ipv6_block))), "SubnetError variant should include the exact IP range that overlaps" ); let new_row = VpcSubnet::new( @@ -513,7 +511,7 @@ mod test { .expect_err("Should not be able to insert VPC Subnet with overlapping IPv4 range"); assert_eq!( err, - SubnetError::OverlappingIpRange(IpNetwork::from(ipv4_block.0)), + SubnetError::OverlappingIpRange(ipnetwork::IpNetwork::from(oxnet::IpNet::from(ipv4_block))), "SubnetError variant should include the exact IP range that overlaps" ); diff --git a/nexus/networking/src/firewall_rules.rs b/nexus/networking/src/firewall_rules.rs index 484c1481e8..a656c673ca 100644 --- a/nexus/networking/src/firewall_rules.rs +++ b/nexus/networking/src/firewall_rules.rs @@ -362,7 +362,7 @@ pub async fn resolve_firewall_rules_for_sled_agent( } external::VpcFirewallRuleHostFilter::Subnet(name) => { for subnet in subnet_networks - .get(&name) + .get(name) .unwrap_or(&no_networks) { host_addrs.push( @@ -382,7 +382,7 @@ pub async fn resolve_firewall_rules_for_sled_agent( } external::VpcFirewallRuleHostFilter::Vpc(name) => { for interface in vpc_interfaces - .get(&name) + .get(name) .unwrap_or(&no_interfaces) { host_addrs.push( diff --git a/nexus/reconfigurator/execution/Cargo.toml b/nexus/reconfigurator/execution/Cargo.toml index 2ea39d5a3e..26ac14e239 100644 --- a/nexus/reconfigurator/execution/Cargo.toml +++ b/nexus/reconfigurator/execution/Cargo.toml @@ -19,6 +19,7 @@ nexus-networking.workspace = true nexus-types.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true +oxnet.workspace = true reqwest.workspace = true sled-agent-client.workspace = true slog.workspace = true diff --git a/nexus/reconfigurator/execution/src/external_networking.rs b/nexus/reconfigurator/execution/src/external_networking.rs index 40ad65816e..e00456c59c 100644 --- a/nexus/reconfigurator/execution/src/external_networking.rs +++ b/nexus/reconfigurator/execution/src/external_networking.rs @@ -443,10 +443,10 @@ mod tests { use omicron_common::address::NEXUS_OPTE_IPV4_SUBNET; use omicron_common::address::NTP_OPTE_IPV4_SUBNET; use omicron_common::address::NUM_SOURCE_NAT_PORTS; - use omicron_common::api::external::IpNet; use omicron_common::api::external::MacAddr; use omicron_common::api::external::Vni; use omicron_uuid_kinds::ExternalIpUuid; + use oxnet::IpNet; use std::net::IpAddr; use std::net::Ipv6Addr; use std::net::SocketAddr; diff --git a/nexus/src/app/allow_list.rs b/nexus/src/app/allow_list.rs index b113ed886b..6a3599f796 100644 --- a/nexus/src/app/allow_list.rs +++ b/nexus/src/app/allow_list.rs @@ -53,7 +53,7 @@ impl super::Nexus { let mut contains_remote = false; for entry in list.iter() { contains_remote = entry.contains(remote_addr); - if entry.ip().is_unspecified() { + if entry.addr().is_unspecified() { return Err(Error::invalid_request( "Source IP allowlist may not contain the \ unspecified address. Use \"any\" to allow \ diff --git a/nexus/src/app/background/sync_service_zone_nat.rs b/nexus/src/app/background/sync_service_zone_nat.rs index d1bb9955d7..f99f30b51f 100644 --- a/nexus/src/app/background/sync_service_zone_nat.rs +++ b/nexus/src/app/background/sync_service_zone_nat.rs @@ -125,9 +125,7 @@ impl BackgroundTask for ServiceZoneNatTracker { } }; - let sled_address = external::Ipv6Net( - ipnetwork::Ipv6Network::new(*sled.ip, 128).unwrap(), - ); + let sled_address = oxnet::Ipv6Net::host_net(*sled.ip); let zones_config: sled_agent_client::types::OmicronZonesConfig = zones_found.zones; @@ -152,16 +150,14 @@ impl BackgroundTask for ServiceZoneNatTracker { }; let external_address = - ipnetwork::Ipv4Network::new(external_ip, 32) + oxnet::Ipv4Net::new(external_ip, 32) .unwrap(); let (snat_first_port, snat_last_port) = snat_cfg.port_range_raw(); let nat_value = Ipv4NatValues { external_address: nexus_db_model::Ipv4Net( - omicron_common::api::external::Ipv4Net( external_address, - ), ), first_port: snat_first_port.into(), last_port: snat_last_port.into(), @@ -187,14 +183,12 @@ impl BackgroundTask for ServiceZoneNatTracker { }; let external_address = - ipnetwork::Ipv4Network::new(external_ip, 32) + oxnet::Ipv4Net::new(external_ip, 32) .unwrap(); let nat_value = Ipv4NatValues { external_address: nexus_db_model::Ipv4Net( - omicron_common::api::external::Ipv4Net( external_address, - ), ), first_port: MIN_PORT.into(), last_port: MAX_PORT.into(), @@ -234,14 +228,12 @@ impl BackgroundTask for ServiceZoneNatTracker { }; let external_address = - ipnetwork::Ipv4Network::new(external_ip, 32) + oxnet::Ipv4Net::new(external_ip, 32) .unwrap(); let nat_value = Ipv4NatValues { external_address: nexus_db_model::Ipv4Net( - omicron_common::api::external::Ipv4Net( external_address, - ), ), first_port: MIN_PORT.into(), last_port: MAX_PORT.into(), diff --git a/nexus/src/app/bgp.rs b/nexus/src/app/bgp.rs index d41eaf2e6a..b79adb93ec 100644 --- a/nexus/src/app/bgp.rs +++ b/nexus/src/app/bgp.rs @@ -10,9 +10,9 @@ use nexus_db_queries::context::OpContext; use omicron_common::api::external::http_pagination::PaginatedBy; use omicron_common::api::external::{ self, BgpImportedRouteIpv4, BgpMessageHistory, BgpPeerStatus, CreateResult, - DeleteResult, Ipv4Net, ListResultVec, LookupResult, NameOrId, - SwitchBgpHistory, + DeleteResult, ListResultVec, LookupResult, NameOrId, SwitchBgpHistory, }; +use oxnet::Ipv4Net; use std::net::IpAddr; impl super::Nexus { @@ -202,8 +202,7 @@ impl super::Nexus { { Ok(result) => { for (prefix, paths) in result.into_inner().iter() { - let ipnet: ipnetwork::Ipv4Network = match prefix.parse() - { + let ipnet = match prefix.parse() { Ok(p) => p, Err(e) => { error!( @@ -220,7 +219,7 @@ impl super::Nexus { }; let x = BgpImportedRouteIpv4 { switch: *switch, - prefix: Ipv4Net(ipnet), + prefix: ipnet, id: p .bgp .as_ref() diff --git a/nexus/src/app/instance_network.rs b/nexus/src/app/instance_network.rs index 2c258c8064..2e141d5b75 100644 --- a/nexus/src/app/instance_network.rs +++ b/nexus/src/app/instance_network.rs @@ -21,12 +21,12 @@ use nexus_db_queries::db::DataStore; use nexus_types::deployment::SledFilter; use omicron_common::api::external::DataPageParams; use omicron_common::api::external::Error; -use omicron_common::api::external::Ipv4Net; -use omicron_common::api::external::Ipv6Net; use omicron_common::api::internal::nexus; use omicron_common::api::internal::shared::NetworkInterface; use omicron_common::api::internal::shared::SwitchLocation; use omicron_common::retry_until_known_result; +use oxnet::Ipv4Net; +use oxnet::Ipv6Net; use sled_agent_client::types::DeleteVirtualNetworkInterfaceHost; use sled_agent_client::types::SetVirtualNetworkInterfaceHost; use std::collections::HashSet; @@ -549,8 +549,7 @@ pub(crate) async fn instance_ensure_dpd_config( )); } - let sled_address = - Ipv6Net(Ipv6Network::new(*sled_ip_address.ip(), 128).unwrap()); + let sled_address = Ipv6Net::new(*sled_ip_address.ip(), 128).unwrap(); // If all of our IPs are attached or are guaranteed to be owned // by the saga calling this fn, then we need to disregard and @@ -691,7 +690,7 @@ pub(crate) async fn probe_ensure_dpd_config( } } - let sled_address = Ipv6Net(Ipv6Network::new(sled_ip_address, 128).unwrap()); + let sled_address = Ipv6Net::new(sled_ip_address, 128).unwrap(); for target_ip in ips .iter() @@ -1295,7 +1294,8 @@ async fn ensure_nat_entry( match target_ip.ip { IpNetwork::V4(v4net) => { let nat_entry = Ipv4NatValues { - external_address: Ipv4Net(v4net).into(), + // TODO could simplify this conversion? + external_address: Ipv4Net::from(v4net).into(), first_port: target_ip.first_port, last_port: target_ip.last_port, sled_address: sled_address.into(), diff --git a/nexus/src/app/sagas/vpc_create.rs b/nexus/src/app/sagas/vpc_create.rs index 6b48e4087a..4d3e5bd474 100644 --- a/nexus/src/app/sagas/vpc_create.rs +++ b/nexus/src/app/sagas/vpc_create.rs @@ -291,15 +291,13 @@ async fn svc_create_subnet( // Allocate the first /64 sub-range from the requested or created // prefix. - let ipv6_block = external::Ipv6Net( - ipnetwork::Ipv6Network::new(db_vpc.ipv6_prefix.network(), 64) - .map_err(|_| { - external::Error::internal_error( - "Failed to allocate default IPv6 subnet", - ) - }) - .map_err(ActionError::action_failed)?, - ); + let ipv6_block = oxnet::Ipv6Net::new(db_vpc.ipv6_prefix.network(), 64) + .map_err(|_| { + external::Error::internal_error( + "Failed to allocate default IPv6 subnet", + ) + }) + .map_err(ActionError::action_failed)?; let subnet = db::model::VpcSubnet::new( default_subnet_id, diff --git a/nexus/src/app/switch_interface.rs b/nexus/src/app/switch_interface.rs index c3ce0f553c..bb4cba4c7b 100644 --- a/nexus/src/app/switch_interface.rs +++ b/nexus/src/app/switch_interface.rs @@ -11,8 +11,9 @@ use nexus_db_queries::db::lookup; use nexus_db_queries::db::lookup::LookupPath; use omicron_common::api::external::LookupResult; use omicron_common::api::external::{ - CreateResult, DataPageParams, DeleteResult, Error, IpNet, ListResultVec, + CreateResult, DataPageParams, DeleteResult, Error, ListResultVec, }; +use oxnet::IpNet; use std::sync::Arc; use uuid::Uuid; diff --git a/nexus/src/app/vpc_subnet.rs b/nexus/src/app/vpc_subnet.rs index 4c5a569201..9dbd617ae4 100644 --- a/nexus/src/app/vpc_subnet.rs +++ b/nexus/src/app/vpc_subnet.rs @@ -19,6 +19,7 @@ use omicron_common::api::external::http_pagination::PaginatedBy; use omicron_common::api::external::CreateResult; use omicron_common::api::external::DeleteResult; use omicron_common::api::external::Error; +use omicron_common::api::external::Ipv6NetExt; use omicron_common::api::external::ListResultVec; use omicron_common::api::external::LookupResult; use omicron_common::api::external::NameOrId; @@ -116,7 +117,7 @@ impl super::Nexus { let ipv6_block = db_vpc .ipv6_prefix .random_subnet( - external::Ipv6Net::VPC_SUBNET_IPV6_PREFIX_LENGTH, + oxnet::Ipv6Net::VPC_SUBNET_IPV6_PREFIX_LENGTH, ) .map(|block| block.0) .ok_or_else(|| { @@ -148,7 +149,7 @@ impl super::Nexus { self.log, "autogenerated random IPv6 range overlap"; "subnet_id" => ?subnet_id, - "ipv6_block" => %ipv6_block.0 + "ipv6_block" => %ipv6_block ); retry += 1; continue; @@ -193,10 +194,10 @@ impl super::Nexus { if !ipv6_block.is_vpc_subnet(&db_vpc.ipv6_prefix) { return Err(external::Error::invalid_request(&format!( concat!( - "VPC Subnet IPv6 address range '{}' is not valid for ", - "VPC with IPv6 prefix '{}'", - ), - ipv6_block, db_vpc.ipv6_prefix.0 .0, + "VPC Subnet IPv6 address range '{}' is not valid for ", + "VPC with IPv6 prefix '{}'", + ), + ipv6_block, db_vpc.ipv6_prefix.0, ))); } let subnet = db::model::VpcSubnet::new( diff --git a/nexus/src/context.rs b/nexus/src/context.rs index cf2b9d6f17..33a4b6f651 100644 --- a/nexus/src/context.rs +++ b/nexus/src/context.rs @@ -157,7 +157,8 @@ impl ServerContext { // Set up DNS Client let resolver = match config.deployment.internal_dns { nexus_config::InternalDns::FromSubnet { subnet } => { - let az_subnet = Ipv6Subnet::::new(subnet.net().ip()); + let az_subnet = + Ipv6Subnet::::new(subnet.net().addr()); info!( log, "Setting up resolver using DNS servers for subnet: {:?}", diff --git a/nexus/tests/integration_tests/endpoints.rs b/nexus/tests/integration_tests/endpoints.rs index cc73ab088c..7672bbc034 100644 --- a/nexus/tests/integration_tests/endpoints.rs +++ b/nexus/tests/integration_tests/endpoints.rs @@ -30,7 +30,6 @@ use omicron_common::api::external::ByteCount; use omicron_common::api::external::IdentityMetadataCreateParams; use omicron_common::api::external::IdentityMetadataUpdateParams; use omicron_common::api::external::InstanceCpuCount; -use omicron_common::api::external::Ipv4Net; use omicron_common::api::external::Name; use omicron_common::api::external::NameOrId; use omicron_common::api::external::RouteDestination; @@ -201,7 +200,7 @@ pub static DEMO_VPC_SUBNET_CREATE: Lazy = name: DEMO_VPC_SUBNET_NAME.clone(), description: String::from(""), }, - ipv4_block: Ipv4Net("10.1.2.3/8".parse().unwrap()), + ipv4_block: "10.1.2.3/8".parse().unwrap(), ipv6_block: None, }); diff --git a/nexus/tests/integration_tests/instances.rs b/nexus/tests/integration_tests/instances.rs index 08cf195384..5e62cb50da 100644 --- a/nexus/tests/integration_tests/instances.rs +++ b/nexus/tests/integration_tests/instances.rs @@ -56,7 +56,6 @@ use omicron_common::api::external::Instance; use omicron_common::api::external::InstanceCpuCount; use omicron_common::api::external::InstanceNetworkInterface; use omicron_common::api::external::InstanceState; -use omicron_common::api::external::Ipv4Net; use omicron_common::api::external::Name; use omicron_common::api::external::NameOrId; use omicron_common::api::external::Vni; @@ -66,6 +65,7 @@ use omicron_nexus::app::MIN_MEMORY_BYTES_PER_INSTANCE; use omicron_nexus::Nexus; use omicron_nexus::TestInterfaces as _; use omicron_sled_agent::sim::SledAgent; +use oxnet::Ipv4Net; use sled_agent_client::TestInterfaces as _; use std::convert::TryFrom; use std::net::Ipv4Addr; @@ -1712,7 +1712,7 @@ async fn test_instance_with_new_custom_network_interfaces( name: non_default_subnet_name.clone(), description: String::from("A non-default subnet"), }, - ipv4_block: Ipv4Net("172.31.0.0/24".parse().unwrap()), + ipv4_block: "172.31.0.0/24".parse().unwrap(), ipv6_block: None, }; let _response = NexusRequest::objects_post( @@ -1858,7 +1858,7 @@ async fn test_instance_create_delete_network_interface( name: Name::try_from(String::from("secondary")).unwrap(), description: String::from("A secondary VPC subnet"), }, - ipv4_block: Ipv4Net("172.31.0.0/24".parse().unwrap()), + ipv4_block: "172.31.0.0/24".parse().unwrap(), ipv6_block: None, }; let _response = NexusRequest::objects_post( @@ -2099,7 +2099,7 @@ async fn test_instance_update_network_interfaces( name: Name::try_from(String::from("secondary")).unwrap(), description: String::from("A secondary VPC subnet"), }, - ipv4_block: Ipv4Net("172.31.0.0/24".parse().unwrap()), + ipv4_block: "172.31.0.0/24".parse().unwrap(), ipv6_block: None, }; let _response = NexusRequest::objects_post( diff --git a/nexus/tests/integration_tests/subnet_allocation.rs b/nexus/tests/integration_tests/subnet_allocation.rs index d9d015bf26..58ac054eb7 100644 --- a/nexus/tests/integration_tests/subnet_allocation.rs +++ b/nexus/tests/integration_tests/subnet_allocation.rs @@ -22,8 +22,9 @@ use nexus_test_utils_macros::nexus_test; use nexus_types::external_api::params; use omicron_common::api::external::{ ByteCount, IdentityMetadataCreateParams, InstanceCpuCount, - InstanceNetworkInterface, Ipv4Net, + InstanceNetworkInterface, }; +use oxnet::Ipv4Net; use std::net::Ipv4Addr; type ControlPlaneTestContext = @@ -97,7 +98,7 @@ async fn test_subnet_allocation(cptestctx: &ControlPlaneTestContext) { let subnets_url = format!("/v1/vpc-subnets?{}", vpc_selector); let subnet_name = "small"; let network_address = Ipv4Addr::new(192, 168, 42, 0); - let subnet = Ipv4Network::new(network_address, subnet_size) + let subnet = Ipv4Net::new(network_address, subnet_size) .expect("Invalid IPv4 network"); let subnet_create = params::VpcSubnetCreate { identity: IdentityMetadataCreateParams { @@ -105,7 +106,7 @@ async fn test_subnet_allocation(cptestctx: &ControlPlaneTestContext) { description: String::from("a small subnet"), }, // Use the minimum subnet size - ipv4_block: Ipv4Net(subnet), + ipv4_block: subnet, ipv6_block: None, }; NexusRequest::objects_post(client, &subnets_url, &Some(&subnet_create)) diff --git a/nexus/tests/integration_tests/vpc_subnets.rs b/nexus/tests/integration_tests/vpc_subnets.rs index 76cff9ac79..067e7fc691 100644 --- a/nexus/tests/integration_tests/vpc_subnets.rs +++ b/nexus/tests/integration_tests/vpc_subnets.rs @@ -20,8 +20,9 @@ use nexus_test_utils_macros::nexus_test; use nexus_types::external_api::{params, views::VpcSubnet}; use omicron_common::api::external::IdentityMetadataCreateParams; use omicron_common::api::external::IdentityMetadataUpdateParams; -use omicron_common::api::external::Ipv4Net; -use omicron_common::api::external::Ipv6Net; +use omicron_common::api::external::Ipv6NetExt; +use oxnet::Ipv4Net; +use oxnet::Ipv6Net; type ControlPlaneTestContext = nexus_test_utils::ControlPlaneTestContext; @@ -160,16 +161,15 @@ async fn test_vpc_subnets(cptestctx: &ControlPlaneTestContext) { assert_eq!(error.message, "not found: vpc-subnet with name \"subnet1\""); // Create a VPC Subnet. - let ipv4_block = Ipv4Net("10.0.0.0/24".parse().unwrap()); - let other_ipv4_block = Ipv4Net("172.31.0.0/16".parse().unwrap()); + let ipv4_block = "10.0.0.0/24".parse().unwrap(); + let other_ipv4_block = "172.31.0.0/16".parse().unwrap(); // Create the first two available IPv6 address ranges. */ let prefix = vpc.ipv6_prefix.network(); - let ipv6_block = Ipv6Net(ipnetwork::Ipv6Network::new(prefix, 64).unwrap()); + let ipv6_block = Ipv6Net::new(prefix, 64).unwrap(); let mut segments = prefix.segments(); segments[3] = 1; let addr = std::net::Ipv6Addr::from(segments); - let other_ipv6_block = - Some(Ipv6Net(ipnetwork::Ipv6Network::new(addr, 64).unwrap())); + let other_ipv6_block = Some(Ipv6Net::new(addr, 64).unwrap()); let new_subnet = params::VpcSubnetCreate { identity: IdentityMetadataCreateParams { name: subnet_name.parse().unwrap(), @@ -291,7 +291,7 @@ async fn test_vpc_subnets(cptestctx: &ControlPlaneTestContext) { assert_eq!(error.message, "not found: vpc-subnet with name \"subnet2\""); // create second subnet, this time with an autogenerated IPv6 range. - let ipv4_block = Ipv4Net("192.168.0.0/16".parse().unwrap()); + let ipv4_block = "192.168.0.0/16".parse().unwrap(); let new_subnet = params::VpcSubnetCreate { identity: IdentityMetadataCreateParams { name: subnet2_name.parse().unwrap(), @@ -435,10 +435,7 @@ async fn test_vpc_subnets(cptestctx: &ControlPlaneTestContext) { "it's also below the net" ); assert_eq!(subnet_same_name.vpc_id, vpc2.identity.id); - assert_eq!( - subnet_same_name.ipv4_block, - Ipv4Net("192.168.0.0/16".parse().unwrap()) - ); + assert_eq!(subnet_same_name.ipv4_block, "192.168.0.0/16".parse().unwrap()); assert!(subnet_same_name.ipv6_block.is_unique_local()); } diff --git a/nexus/tests/integration_tests/vpcs.rs b/nexus/tests/integration_tests/vpcs.rs index cc9aea4d11..1844c79258 100644 --- a/nexus/tests/integration_tests/vpcs.rs +++ b/nexus/tests/integration_tests/vpcs.rs @@ -18,7 +18,6 @@ use nexus_test_utils_macros::nexus_test; use nexus_types::external_api::{params, views::Vpc}; use omicron_common::api::external::IdentityMetadataCreateParams; use omicron_common::api::external::IdentityMetadataUpdateParams; -use omicron_common::api::external::Ipv6Net; type ControlPlaneTestContext = nexus_test_utils::ControlPlaneTestContext; @@ -76,7 +75,7 @@ async fn test_vpcs(cptestctx: &ControlPlaneTestContext) { // Make sure creating a VPC fails if we specify an IPv6 prefix that is // not a valid ULA range. - let bad_prefix = Ipv6Net("2000:1000::/48".parse().unwrap()); + let bad_prefix = "2000:1000::/48".parse().unwrap(); NexusRequest::new( RequestBuilder::new(client, Method::POST, &vpcs_url) .expect_status(Some(StatusCode::BAD_REQUEST)) From f3ba1fed50d64d634e9c820caaf79cc2fd581bdc Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 8 May 2024 15:08:40 -0700 Subject: [PATCH 05/23] clean up lint --- common/src/address.rs | 36 +++++++++---------- common/src/api/external/mod.rs | 1 - internal-dns/src/resolver.rs | 2 +- .../src/db/queries/network_interface.rs | 2 -- .../app/background/sync_service_zone_nat.rs | 1 - nexus/src/app/bgp.rs | 1 - nexus/src/app/instance_network.rs | 1 - nexus/tests/integration_tests/instances.rs | 1 - .../integration_tests/subnet_allocation.rs | 1 - nexus/tests/integration_tests/vpc_subnets.rs | 1 - sled-agent/src/rack_setup/plan/service.rs | 6 ++-- 11 files changed, 22 insertions(+), 31 deletions(-) diff --git a/common/src/address.rs b/common/src/address.rs index d92a84d2f2..ba453951aa 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -8,7 +8,7 @@ //! and Nexus, who need to agree upon addressing schemes. use crate::api::external::{self, Error}; -use ipnetwork::{Ipv4Network, Ipv6Network}; +use ipnetwork::Ipv6Network; use once_cell::sync::Lazy; use oxnet::{Ipv4Net, Ipv6Net}; use schemars::JsonSchema; @@ -247,29 +247,29 @@ pub struct DnsSubnet { } impl DnsSubnet { + // TODO why are we returning a subnet? /// Returns the DNS server address within the subnet. /// /// This is the first address within the subnet. - pub fn dns_address(&self) -> Ipv6Addr { - // Ipv6Network::new( - // self.subnet.net().iter().nth(DNS_ADDRESS_INDEX).unwrap(), - // SLED_PREFIX, - // ) - // .unwrap() - todo!() + pub fn dns_address(&self) -> Ipv6Net { + Ipv6Net::new( + self.subnet.net().iter().nth(DNS_ADDRESS_INDEX).unwrap(), + SLED_PREFIX, + ) + .unwrap() } + // TODO why are we returning a subnet? /// Returns the address which the Global Zone should create /// to be able to contact the DNS server. /// /// This is the second address within the subnet. - pub fn gz_address(&self) -> Ipv6Addr { - // Ipv6Network::new( - // self.subnet.net().iter().nth(GZ_ADDRESS_INDEX).unwrap(), - // SLED_PREFIX, - // ) - // .unwrap() - todo!() + pub fn gz_address(&self) -> Ipv6Net { + Ipv6Net::new( + self.subnet.net().iter().nth(GZ_ADDRESS_INDEX).unwrap(), + SLED_PREFIX, + ) + .unwrap() } } @@ -308,7 +308,7 @@ pub fn get_internal_dns_server_addresses(addr: Ipv6Addr) -> Vec { &reserved_rack_subnet.get_dns_subnets()[0..DNS_REDUNDANCY]; dns_subnets .iter() - .map(|dns_subnet| IpAddr::from(dns_subnet.dns_address())) + .map(|dns_subnet| IpAddr::from(dns_subnet.dns_address().addr())) .collect() } @@ -690,11 +690,11 @@ mod test { // The DNS address and GZ address should be only differing by one. assert_eq!( - "fd00:1122:3344:0001::1".parse::().unwrap(), + "fd00:1122:3344:0001::1/64".parse::().unwrap(), dns_subnets[0].dns_address(), ); assert_eq!( - "fd00:1122:3344:0001::2".parse::().unwrap(), + "fd00:1122:3344:0001::2/64".parse::().unwrap(), dns_subnets[0].gz_address(), ); } diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index c7982b4433..56ccc4c909 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -40,7 +40,6 @@ use std::fmt::Formatter; use std::fmt::Result as FormatResult; use std::net::IpAddr; use std::net::Ipv4Addr; -use std::net::Ipv6Addr; use std::num::{NonZeroU16, NonZeroU32}; use std::str::FromStr; use uuid::Uuid; diff --git a/internal-dns/src/resolver.rs b/internal-dns/src/resolver.rs index cf5def01c5..670b4b420c 100644 --- a/internal-dns/src/resolver.rs +++ b/internal-dns/src/resolver.rs @@ -118,7 +118,7 @@ impl Resolver { .get_dns_subnets() .into_iter() .map(|dns_subnet| { - let ip_addr = IpAddr::V6(dns_subnet.dns_address()); + let ip_addr = IpAddr::V6(dns_subnet.dns_address().addr()); SocketAddr::new(ip_addr, DNS_PORT) }) .collect() diff --git a/nexus/db-queries/src/db/queries/network_interface.rs b/nexus/db-queries/src/db/queries/network_interface.rs index bf0b1722b5..091ecaff23 100644 --- a/nexus/db-queries/src/db/queries/network_interface.rs +++ b/nexus/db-queries/src/db/queries/network_interface.rs @@ -1859,8 +1859,6 @@ mod tests { use crate::db::queries::network_interface::NextMacShifts; use async_bb8_diesel::AsyncRunQueryDsl; use dropshot::test_util::LogContext; - use ipnetwork::Ipv4Network; - use ipnetwork::Ipv6Network; use model::NetworkInterfaceKind; use nexus_test_utils::db::test_setup_database; use nexus_types::external_api::params; diff --git a/nexus/src/app/background/sync_service_zone_nat.rs b/nexus/src/app/background/sync_service_zone_nat.rs index f99f30b51f..b0a4c8cef2 100644 --- a/nexus/src/app/background/sync_service_zone_nat.rs +++ b/nexus/src/app/background/sync_service_zone_nat.rs @@ -19,7 +19,6 @@ use nexus_db_queries::context::OpContext; use nexus_db_queries::db::lookup::LookupPath; use nexus_db_queries::db::DataStore; use omicron_common::address::{MAX_PORT, MIN_PORT}; -use omicron_common::api::external; use omicron_uuid_kinds::GenericUuid; use serde_json::json; use sled_agent_client::types::OmicronZoneType; diff --git a/nexus/src/app/bgp.rs b/nexus/src/app/bgp.rs index b79adb93ec..b6e3f25263 100644 --- a/nexus/src/app/bgp.rs +++ b/nexus/src/app/bgp.rs @@ -12,7 +12,6 @@ use omicron_common::api::external::{ self, BgpImportedRouteIpv4, BgpMessageHistory, BgpPeerStatus, CreateResult, DeleteResult, ListResultVec, LookupResult, NameOrId, SwitchBgpHistory, }; -use oxnet::Ipv4Net; use std::net::IpAddr; impl super::Nexus { diff --git a/nexus/src/app/instance_network.rs b/nexus/src/app/instance_network.rs index 2e141d5b75..ea65526b2d 100644 --- a/nexus/src/app/instance_network.rs +++ b/nexus/src/app/instance_network.rs @@ -6,7 +6,6 @@ use crate::app::switch_port; use ipnetwork::IpNetwork; -use ipnetwork::Ipv6Network; use nexus_db_model::ExternalIp; use nexus_db_model::IpAttachState; use nexus_db_model::Ipv4NatEntry; diff --git a/nexus/tests/integration_tests/instances.rs b/nexus/tests/integration_tests/instances.rs index 5e62cb50da..bfebdba9bd 100644 --- a/nexus/tests/integration_tests/instances.rs +++ b/nexus/tests/integration_tests/instances.rs @@ -65,7 +65,6 @@ use omicron_nexus::app::MIN_MEMORY_BYTES_PER_INSTANCE; use omicron_nexus::Nexus; use omicron_nexus::TestInterfaces as _; use omicron_sled_agent::sim::SledAgent; -use oxnet::Ipv4Net; use sled_agent_client::TestInterfaces as _; use std::convert::TryFrom; use std::net::Ipv4Addr; diff --git a/nexus/tests/integration_tests/subnet_allocation.rs b/nexus/tests/integration_tests/subnet_allocation.rs index 58ac054eb7..c445697d4e 100644 --- a/nexus/tests/integration_tests/subnet_allocation.rs +++ b/nexus/tests/integration_tests/subnet_allocation.rs @@ -9,7 +9,6 @@ use dropshot::test_util::ClientTestContext; use dropshot::HttpErrorResponseBody; use http::method::Method; use http::StatusCode; -use ipnetwork::Ipv4Network; use nexus_config::NUM_INITIAL_RESERVED_IP_ADDRESSES; use nexus_test_utils::http_testing::AuthnMode; use nexus_test_utils::http_testing::NexusRequest; diff --git a/nexus/tests/integration_tests/vpc_subnets.rs b/nexus/tests/integration_tests/vpc_subnets.rs index 067e7fc691..9314decd46 100644 --- a/nexus/tests/integration_tests/vpc_subnets.rs +++ b/nexus/tests/integration_tests/vpc_subnets.rs @@ -21,7 +21,6 @@ use nexus_types::external_api::{params, views::VpcSubnet}; use omicron_common::api::external::IdentityMetadataCreateParams; use omicron_common::api::external::IdentityMetadataUpdateParams; use omicron_common::api::external::Ipv6NetExt; -use oxnet::Ipv4Net; use oxnet::Ipv6Net; type ControlPlaneTestContext = diff --git a/sled-agent/src/rack_setup/plan/service.rs b/sled-agent/src/rack_setup/plan/service.rs index 6e3c525567..6eba6b58b9 100644 --- a/sled-agent/src/rack_setup/plan/service.rs +++ b/sled-agent/src/rack_setup/plan/service.rs @@ -384,11 +384,11 @@ impl Plan { &reserved_rack_subnet.get_dns_subnets()[0..DNS_REDUNDANCY]; let rack_dns_servers = dns_subnets .into_iter() - .map(|dns_subnet| dns_subnet.dns_address().into()) + .map(|dns_subnet| dns_subnet.dns_address().addr().into()) .collect::>(); for i in 0..dns_subnets.len() { let dns_subnet = &dns_subnets[i]; - let ip = dns_subnet.dns_address(); + let ip = dns_subnet.dns_address().addr(); let sled = { let which_sled = sled_allocator.next().ok_or(PlanError::NotEnoughSleds)?; @@ -419,7 +419,7 @@ impl Plan { }, http_address, dns_address, - gz_address: dns_subnet.gz_address(), + gz_address: dns_subnet.gz_address().addr(), gz_address_index: i.try_into().expect("Giant indices?"), }, }); From 48aa546e07a854c8dc51607dd6dcce8e4e1c63e3 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 11:37:23 -0700 Subject: [PATCH 06/23] build more --- Cargo.lock | 195 +++++++++--------- clients/ddm-admin-client/src/lib.rs | 2 +- common/src/address.rs | 8 +- common/src/api/external/mod.rs | 4 +- illumos-utils/src/opte/firewall_rules.rs | 12 +- illumos-utils/src/opte/port_manager.rs | 3 +- nexus/db-model/src/ipv4net.rs | 4 +- nexus/db-model/src/ipv6net.rs | 8 +- nexus/db-model/src/lib.rs | 6 +- .../src/db/datastore/network_interface.rs | 2 +- nexus/db-queries/src/db/datastore/rack.rs | 18 +- nexus/db-queries/src/db/datastore/vpc.rs | 2 +- .../src/db/queries/network_interface.rs | 22 +- nexus/defaults/src/lib.rs | 2 +- .../execution/src/external_networking.rs | 3 - .../planning/src/blueprint_builder/builder.rs | 6 +- nexus/src/app/allow_list.rs | 2 +- nexus/src/app/sagas/vpc_create.rs | 2 +- nexus/src/app/vpc_subnet.rs | 6 +- nexus/test-utils/src/lib.rs | 4 +- .../integration_tests/subnet_allocation.rs | 12 +- nexus/tests/integration_tests/vpc_subnets.rs | 4 +- nexus/tests/integration_tests/vpcs.rs | 2 +- sled-agent/src/bootstrap/early_networking.rs | 8 +- sled-agent/src/bootstrap/server.rs | 2 +- sled-agent/src/rack_setup/plan/service.rs | 10 +- sled-agent/src/services.rs | 2 +- sled-agent/src/sim/server.rs | 4 +- 28 files changed, 179 insertions(+), 176 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7334543ace..e47365b0ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,7 +165,7 @@ dependencies = [ "omicron-workspace-hack", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -272,7 +272,7 @@ checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -294,7 +294,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -305,7 +305,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -358,7 +358,7 @@ dependencies = [ "quote", "serde", "serde_tokenstream 0.2.0", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -517,7 +517,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.60", + "syn 2.0.64", "which", ] @@ -1049,7 +1049,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1535,7 +1535,7 @@ checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1559,7 +1559,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1570,7 +1570,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1604,7 +1604,7 @@ dependencies = [ "quote", "serde", "serde_tokenstream 0.2.0", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1647,7 +1647,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1680,7 +1680,7 @@ checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1701,7 +1701,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1722,7 +1722,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1732,7 +1732,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1756,7 +1756,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1820,7 +1820,7 @@ dependencies = [ "diesel_table_macro_syntax", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -1829,7 +1829,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" dependencies = [ - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -2044,7 +2044,7 @@ dependencies = [ [[package]] name = "dropshot" -version = "0.10.1-dev" +version = "0.10.2-dev" dependencies = [ "async-stream", "async-trait", @@ -2089,13 +2089,13 @@ dependencies = [ [[package]] name = "dropshot_endpoint" -version = "0.10.1-dev" +version = "0.10.2-dev" dependencies = [ "proc-macro2", "quote", "serde", "serde_tokenstream 0.2.0", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -2508,7 +2508,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -2619,7 +2619,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -3305,7 +3305,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.6", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -3899,7 +3899,7 @@ version = "0.1.0" source = "git+https://github.com/oxidecomputer/opte?rev=7ee353a470ea59529ee1b34729681da887aa88ce#7ee353a470ea59529ee1b34729681da887aa88ce" dependencies = [ "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -4377,7 +4377,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -4696,7 +4696,7 @@ dependencies = [ "omicron-workspace-hack", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -4893,7 +4893,7 @@ version = "0.1.0" dependencies = [ "omicron-workspace-hack", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -5063,7 +5063,7 @@ checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -5847,7 +5847,7 @@ dependencies = [ "string_cache", "subtle", "syn 1.0.109", - "syn 2.0.60", + "syn 2.0.64", "time", "time-macros", "tokio", @@ -5965,7 +5965,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -6257,7 +6257,7 @@ dependencies = [ "omicron-workspace-hack", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -6437,7 +6437,7 @@ dependencies = [ "regex", "regex-syntax 0.8.2", "structmeta 0.3.0", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -6482,9 +6482,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "path-slash" @@ -6611,7 +6611,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -6681,7 +6681,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -6951,7 +6951,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ac2cf0f2e4f42b49f5ffd07dae8d746508ef7526c13940e5f524012ae6c6550" dependencies = [ "proc-macro2", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -7008,7 +7008,7 @@ dependencies = [ [[package]] name = "progenitor" -version = "0.6.0" +version = "0.7.0" dependencies = [ "progenitor-client", "progenitor-impl", @@ -7018,7 +7018,7 @@ dependencies = [ [[package]] name = "progenitor-client" -version = "0.6.0" +version = "0.7.0" dependencies = [ "bytes", "futures-core", @@ -7031,7 +7031,7 @@ dependencies = [ [[package]] name = "progenitor-impl" -version = "0.6.0" +version = "0.7.0" dependencies = [ "getopts", "heck 0.5.0", @@ -7044,7 +7044,7 @@ dependencies = [ "schemars", "serde", "serde_json", - "syn 2.0.60", + "syn 2.0.64", "thiserror", "typify", "unicode-ident", @@ -7052,7 +7052,7 @@ dependencies = [ [[package]] name = "progenitor-macro" -version = "0.6.0" +version = "0.7.0" dependencies = [ "openapiv3", "proc-macro2", @@ -7063,7 +7063,7 @@ dependencies = [ "serde_json", "serde_tokenstream 0.2.0", "serde_yaml", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -7543,7 +7543,7 @@ checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -7799,7 +7799,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.60", + "syn 2.0.64", "unicode-ident", ] @@ -8180,9 +8180,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.17" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f55c82c700538496bdc329bb4918a81f87cc8888811bd123cf325a0f2f8d309" +checksum = "fc6e7ed6919cb46507fb01ff1654309219f62b4d603822501b0b80d42f6f21ef" dependencies = [ "bytes", "chrono", @@ -8195,14 +8195,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.17" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83263746fe5e32097f06356968a077f96089739c927a61450efa069905eec108" +checksum = "185f2b7aa7e02d418e453790dde16890256bbd2bcd04b7dc5348811052b53f49" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8228,7 +8228,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8304,9 +8304,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.200" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" dependencies = [ "serde_derive", ] @@ -8351,13 +8351,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.200" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8368,7 +8368,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8382,9 +8382,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -8418,7 +8418,7 @@ checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8450,7 +8450,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8492,7 +8492,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8841,7 +8841,7 @@ source = "git+https://github.com/oxidecomputer/slog-error-chain?branch=main#15f6 dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -8968,7 +8968,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9095,7 +9095,7 @@ checksum = "01b2e185515564f15375f593fb966b5718bc624ba77fe49fa4616ad619690554" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9105,7 +9105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ff9eaf853dec4c8802325d8b6d3dffa86cc707fd7a1a4cdbf416e13b061787a" dependencies = [ "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9196,7 +9196,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive 0.2.0", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9208,7 +9208,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive 0.3.0", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9219,7 +9219,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9230,7 +9230,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9265,7 +9265,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9278,7 +9278,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9325,9 +9325,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f" dependencies = [ "proc-macro2", "quote", @@ -9513,7 +9513,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta 0.2.0", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9544,7 +9544,7 @@ checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -9732,7 +9732,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -10010,7 +10010,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -10267,8 +10267,8 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "typify" -version = "0.0.16" -source = "git+https://github.com/oxidecomputer/typify#f7442947ca90eb97af6446a90e73600a7adc191b" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/typify#ad1296f6ceb998ae8c247d999b7828703a232bdd" dependencies = [ "typify-impl", "typify-macro", @@ -10276,8 +10276,8 @@ dependencies = [ [[package]] name = "typify-impl" -version = "0.0.16" -source = "git+https://github.com/oxidecomputer/typify#f7442947ca90eb97af6446a90e73600a7adc191b" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/typify#ad1296f6ceb998ae8c247d999b7828703a232bdd" dependencies = [ "heck 0.5.0", "log", @@ -10285,24 +10285,27 @@ dependencies = [ "quote", "regress", "schemars", + "semver 1.0.22", + "serde", "serde_json", - "syn 2.0.60", + "syn 2.0.64", "thiserror", "unicode-ident", ] [[package]] name = "typify-macro" -version = "0.0.16" -source = "git+https://github.com/oxidecomputer/typify#f7442947ca90eb97af6446a90e73600a7adc191b" +version = "0.1.0" +source = "git+https://github.com/oxidecomputer/typify#ad1296f6ceb998ae8c247d999b7828703a232bdd" dependencies = [ "proc-macro2", "quote", "schemars", + "semver 1.0.22", "serde", "serde_json", "serde_tokenstream 0.2.0", - "syn 2.0.60", + "syn 2.0.64", "typify-impl", ] @@ -10536,7 +10539,7 @@ dependencies = [ "proc-macro2", "quote", "serde_tokenstream 0.2.0", - "syn 2.0.60", + "syn 2.0.64", "usdt-impl 0.5.0", ] @@ -10574,7 +10577,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.60", + "syn 2.0.64", "thiserror", "thread-id", "version_check", @@ -10604,7 +10607,7 @@ dependencies = [ "proc-macro2", "quote", "serde_tokenstream 0.2.0", - "syn 2.0.60", + "syn 2.0.64", "usdt-impl 0.5.0", ] @@ -10783,7 +10786,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", "wasm-bindgen-shared", ] @@ -10817,7 +10820,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -11406,7 +11409,7 @@ checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -11417,7 +11420,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] @@ -11437,7 +11440,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.64", ] [[package]] diff --git a/clients/ddm-admin-client/src/lib.rs b/clients/ddm-admin-client/src/lib.rs index 5be2dd53bd..b926ee2971 100644 --- a/clients/ddm-admin-client/src/lib.rs +++ b/clients/ddm-admin-client/src/lib.rs @@ -82,7 +82,7 @@ impl Client { let me = self.clone(); tokio::spawn(async move { let prefix = - Ipv6Prefix { addr: address.net().network(), len: SLED_PREFIX }; + Ipv6Prefix { addr: address.net().prefix(), len: SLED_PREFIX }; retry_notify(retry_policy_internal_service_aggressive(), || async { info!( me.log, "Sending prefix to ddmd for advertisement"; diff --git a/common/src/address.rs b/common/src/address.rs index ba453951aa..900fa76079 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -198,7 +198,7 @@ impl Ipv6Subnet { // Create a network with the compile-time prefix length. let net = Ipv6Net::new(addr, N).unwrap(); // Ensure the address is set to within-prefix only components. - let net = Ipv6Net::new(net.network(), N).unwrap(); + let net = Ipv6Net::new(net.prefix(), N).unwrap(); Self { net } } @@ -228,13 +228,13 @@ impl<'de, const N: u8> Deserialize<'de> for Ipv6Subnet { } let Inner { net } = Inner::deserialize(deserializer)?; - if net.prefix() == N { + if net.width() == N { Ok(Self { net }) } else { Err(::custom(format!( "expected prefix {} but found {}", N, - net.prefix(), + net.width(), ))) } } @@ -340,7 +340,7 @@ pub fn get_64_subnet( rack_subnet: Ipv6Subnet, index: u8, ) -> Ipv6Subnet { - let mut rack_network = rack_subnet.net().network().octets(); + let mut rack_network = rack_subnet.net().addr().octets(); // To set bits distinguishing the /64 from the /56, we modify the 7th octet. rack_network[7] = index; diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index 56ccc4c909..56297af077 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -1242,13 +1242,13 @@ impl Ipv6NetExt for oxnet::Ipv6Net { fn is_vpc_prefix(&self) -> bool { // /// The prefix length for all VPC subnets // pub const VPC_SUBNET_IPV6_PREFIX_LENGTH: u8 = 64; - self.is_unique_local() && self.prefix() == Self::VPC_IPV6_PREFIX_LENGTH + self.is_unique_local() && self.width() == Self::VPC_IPV6_PREFIX_LENGTH } fn is_vpc_subnet(&self, vpc_prefix: &Self) -> bool { self.is_unique_local() && self.is_subnet_of(vpc_prefix) - && self.prefix() == Self::VPC_SUBNET_IPV6_PREFIX_LENGTH + && self.width() == Self::VPC_SUBNET_IPV6_PREFIX_LENGTH } } diff --git a/illumos-utils/src/opte/firewall_rules.rs b/illumos-utils/src/opte/firewall_rules.rs index abb81ca927..1df0e7421a 100644 --- a/illumos-utils/src/opte/firewall_rules.rs +++ b/illumos-utils/src/opte/firewall_rules.rs @@ -65,26 +65,22 @@ impl FromVpcFirewallRule for VpcFirewallRule { Some(ref hosts) if !hosts.is_empty() => hosts .iter() .map(|host| match host { - HostIdentifier::Ip(IpNet::V4(net)) - if net.prefix() == 32 => - { + HostIdentifier::Ip(IpNet::V4(net)) if net.is_host_net() => { Address::Ip(IpAddr::Ip4(net.addr().into())) } HostIdentifier::Ip(IpNet::V4(net)) => { Address::Subnet(IpCidr::Ip4(Ipv4Cidr::new( net.addr().into(), - Ipv4PrefixLen::new(net.prefix()).unwrap(), + Ipv4PrefixLen::new(net.width()).unwrap(), ))) } - HostIdentifier::Ip(IpNet::V6(net)) - if net.prefix() == 128 => - { + HostIdentifier::Ip(IpNet::V6(net)) if net.is_host_net() => { Address::Ip(IpAddr::Ip6(net.addr().into())) } HostIdentifier::Ip(IpNet::V6(net)) => { Address::Subnet(IpCidr::Ip6(Ipv6Cidr::new( net.addr().into(), - Ipv6PrefixLen::new(net.prefix()).unwrap(), + Ipv6PrefixLen::new(net.width()).unwrap(), ))) } HostIdentifier::Vpc(vni) => { diff --git a/illumos-utils/src/opte/port_manager.rs b/illumos-utils/src/opte/port_manager.rs index ffc92b87b2..03c51c321d 100644 --- a/illumos-utils/src/opte/port_manager.rs +++ b/illumos-utils/src/opte/port_manager.rs @@ -107,8 +107,7 @@ impl PortManager { ) -> Result<(Port, PortTicket), Error> { let mac = *nic.mac; let vni = Vni::new(nic.vni).unwrap(); - let subnet = - IpNetwork::new(nic.subnet.addr(), nic.subnet.prefix()).unwrap(); + let subnet = IpNetwork::from(nic.subnet); let vpc_subnet = IpCidr::from(subnet); let gateway = Gateway::from_subnet(&subnet); diff --git a/nexus/db-model/src/ipv4net.rs b/nexus/db-model/src/ipv4net.rs index d57f28fd73..b2cf6ffefa 100644 --- a/nexus/db-model/src/ipv4net.rs +++ b/nexus/db-model/src/ipv4net.rs @@ -45,14 +45,14 @@ impl Ipv4Net { } // Only the first N addresses are reserved if self - .iter() + .addr_iter() .take(NUM_INITIAL_RESERVED_IP_ADDRESSES) .any(|this| this == addr) { return Err(RequestAddressError::Reserved); } // Last address in the subnet is reserved - if addr == self.broadcast() { + if addr == self.broadcast().expect("narrower subnet than expected") { return Err(RequestAddressError::Broadcast); } diff --git a/nexus/db-model/src/ipv6net.rs b/nexus/db-model/src/ipv6net.rs index 376d848c8e..adcf732f42 100644 --- a/nexus/db-model/src/ipv6net.rs +++ b/nexus/db-model/src/ipv6net.rs @@ -47,10 +47,10 @@ impl Ipv6Net { use rand::RngCore; const MAX_IPV6_SUBNET_PREFIX: u8 = 128; - if prefix < self.prefix() || prefix > MAX_IPV6_SUBNET_PREFIX { + if prefix < self.width() || prefix > MAX_IPV6_SUBNET_PREFIX { return None; } - if prefix == self.prefix() { + if prefix == self.width() { return Some(*self); } @@ -71,8 +71,8 @@ impl Ipv6Net { let full_mask = !(u128::MAX >> prefix); // Get the existing network address and mask. - let network = u128::from(self.network()); - let network_mask = u128::from(self.mask()); + let network = u128::from(self.prefix()); + let network_mask = u128::from(self.mask_addr()); // Take random bits _only_ where the new mask is set. let random_mask = full_mask ^ network_mask; diff --git a/nexus/db-model/src/lib.rs b/nexus/db-model/src/lib.rs index ad4f9e8777..f6cc22461a 100644 --- a/nexus/db-model/src/lib.rs +++ b/nexus/db-model/src/lib.rs @@ -511,11 +511,11 @@ mod tests { ); let subnet = base.random_subnet(64).unwrap(); assert_eq!( - subnet.prefix(), + subnet.width(), 64, "random_subnet() returned an incorrect prefix" ); - let octets = subnet.network().octets(); + let octets = subnet.prefix().octets(); const EXPECTED_RANDOM_BYTES: [u8; 8] = [253, 0, 0, 0, 0, 0, 111, 127]; assert_eq!(octets[..8], EXPECTED_RANDOM_BYTES); assert!( @@ -526,7 +526,7 @@ mod tests { base.is_supernet_of(&subnet.0), "random_subnet should generate an actual subnet" ); - assert_eq!(base.random_subnet(base.prefix()), Some(base)); + assert_eq!(base.random_subnet(base.width()), Some(base)); } #[test] diff --git a/nexus/db-queries/src/db/datastore/network_interface.rs b/nexus/db-queries/src/db/datastore/network_interface.rs index abaeab87cf..630899e89f 100644 --- a/nexus/db-queries/src/db/datastore/network_interface.rs +++ b/nexus/db-queries/src/db/datastore/network_interface.rs @@ -838,7 +838,7 @@ mod tests { // Insert 10 Nexus NICs let ip_range = NEXUS_OPTE_IPV4_SUBNET - .iter() + .addr_iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES) .take(10); let mut macs = external::MacAddr::iter_system(); diff --git a/nexus/db-queries/src/db/datastore/rack.rs b/nexus/db-queries/src/db/datastore/rack.rs index aceb2b2135..e3f127891e 100644 --- a/nexus/db-queries/src/db/datastore/rack.rs +++ b/nexus/db-queries/src/db/datastore/rack.rs @@ -1291,22 +1291,22 @@ mod test { let external_dns_ip = IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)); let external_dns_pip = DNS_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 1) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 1) .unwrap(); let external_dns_id = OmicronZoneUuid::new_v4(); let nexus_ip = IpAddr::V4(Ipv4Addr::new(1, 2, 3, 6)); let nexus_pip = NEXUS_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 1) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 1) .unwrap(); let nexus_id = OmicronZoneUuid::new_v4(); let ntp1_ip = IpAddr::V4(Ipv4Addr::new(1, 2, 3, 5)); let ntp1_pip = NTP_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 1) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 1) .unwrap(); let ntp1_id = OmicronZoneUuid::new_v4(); let ntp2_ip = IpAddr::V4(Ipv4Addr::new(1, 2, 3, 5)); let ntp2_pip = NTP_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 2) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 2) .unwrap(); let ntp2_id = OmicronZoneUuid::new_v4(); let ntp3_id = OmicronZoneUuid::new_v4(); @@ -1627,10 +1627,10 @@ mod test { let nexus_id1 = OmicronZoneUuid::new_v4(); let nexus_id2 = OmicronZoneUuid::new_v4(); let nexus_pip1 = NEXUS_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 1) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 1) .unwrap(); let nexus_pip2 = NEXUS_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 2) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 2) .unwrap(); let mut macs = MacAddr::iter_system(); @@ -1899,7 +1899,7 @@ mod test { let nexus_ip = IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)); let nexus_pip = NEXUS_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 1) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 1) .unwrap(); let nexus_id = OmicronZoneUuid::new_v4(); let mut macs = MacAddr::iter_system(); @@ -1997,11 +1997,11 @@ mod test { // Request two services which happen to be using the same IP address. let external_dns_id = OmicronZoneUuid::new_v4(); let external_dns_pip = DNS_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 1) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 1) .unwrap(); let nexus_id = OmicronZoneUuid::new_v4(); let nexus_pip = NEXUS_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 1) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 1) .unwrap(); let mut macs = MacAddr::iter_system(); diff --git a/nexus/db-queries/src/db/datastore/vpc.rs b/nexus/db-queries/src/db/datastore/vpc.rs index 7fe0d8420f..2406bd6a8e 100644 --- a/nexus/db-queries/src/db/datastore/vpc.rs +++ b/nexus/db-queries/src/db/datastore/vpc.rs @@ -1508,7 +1508,7 @@ mod tests { let mut nexus_external_ips = "192.0.2.0/24".parse::().unwrap().iter(); let mut nexus_nic_ips = NEXUS_OPTE_IPV4_SUBNET - .iter() + .addr_iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES) .map(IpAddr::from); let mut nexus_macs = MacAddr::iter_system(); diff --git a/nexus/db-queries/src/db/queries/network_interface.rs b/nexus/db-queries/src/db/queries/network_interface.rs index 091ecaff23..69c1827b6d 100644 --- a/nexus/db-queries/src/db/queries/network_interface.rs +++ b/nexus/db-queries/src/db/queries/network_interface.rs @@ -2019,9 +2019,11 @@ mod tests { self.subnets .iter() .map(|subnet| { - subnet.ipv4_block.size() as usize - - NUM_INITIAL_RESERVED_IP_ADDRESSES - - 1 + let size_minus_1 = match subnet.ipv4_block.size() { + Some(n) => n - 1, + None => u32::MAX, + } as usize; + size_minus_1 - NUM_INITIAL_RESERVED_IP_ADDRESSES }) .collect() } @@ -2134,7 +2136,7 @@ mod tests { let service_id = Uuid::new_v4(); let ip = context.net1.subnets[0] .ipv4_block - .iter() + .addr_iter() .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES) .unwrap(); let interface = IncompleteNetworkInterface::new_service( @@ -2302,7 +2304,7 @@ mod tests { TestContext::new("test_insert_sequential_ip_allocation", 2).await; let addresses = context.net1.subnets[0] .ipv4_block - .iter() + .addr_iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES); for (i, expected_address) in addresses.take(2).enumerate() { @@ -2398,7 +2400,7 @@ mod tests { let service_id = Uuid::new_v4(); let ip = context.net1.subnets[0] .ipv4_block - .iter() + .addr_iter() .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES) .unwrap(); let mac = MacAddr::random_system(); @@ -2433,7 +2435,7 @@ mod tests { let mut used_macs = HashSet::new(); let mut ips = context.net1.subnets[0] .ipv4_block - .iter() + .addr_iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES); for slot in 0..u8::try_from(MAX_NICS_PER_INSTANCE).unwrap() { let service_id = Uuid::new_v4(); @@ -2473,7 +2475,7 @@ mod tests { let mut ips = context.net1.subnets[0] .ipv4_block - .iter() + .addr_iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES); // Insert a service NIC @@ -2533,12 +2535,12 @@ mod tests { let ip0 = context.net1.subnets[0] .ipv4_block - .iter() + .addr_iter() .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES) .unwrap(); let ip1 = context.net1.subnets[1] .ipv4_block - .iter() + .addr_iter() .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES) .unwrap(); diff --git a/nexus/defaults/src/lib.rs b/nexus/defaults/src/lib.rs index f99cf50486..32def47b9e 100644 --- a/nexus/defaults/src/lib.rs +++ b/nexus/defaults/src/lib.rs @@ -86,7 +86,7 @@ mod tests { fn test_random_vpc_ipv6_prefix() { let network = random_vpc_ipv6_prefix().unwrap(); assert!(network.is_vpc_prefix()); - let octets = network.network().octets(); + let octets = network.prefix().octets(); assert!(octets[6..].iter().all(|x| *x == 0)); } } diff --git a/nexus/reconfigurator/execution/src/external_networking.rs b/nexus/reconfigurator/execution/src/external_networking.rs index e00456c59c..fd506e8cde 100644 --- a/nexus/reconfigurator/execution/src/external_networking.rs +++ b/nexus/reconfigurator/execution/src/external_networking.rs @@ -491,7 +491,6 @@ mod tests { }, name: "test-nexus".parse().expect("bad name"), ip: NEXUS_OPTE_IPV4_SUBNET - .iter() .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES) .unwrap() .into(), @@ -517,7 +516,6 @@ mod tests { }, name: "test-external-dns".parse().expect("bad name"), ip: DNS_OPTE_IPV4_SUBNET - .iter() .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES) .unwrap() .into(), @@ -546,7 +544,6 @@ mod tests { }, name: "test-external-ntp".parse().expect("bad name"), ip: NTP_OPTE_IPV4_SUBNET - .iter() .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES) .unwrap() .into(), diff --git a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs index a560c504c7..c6dabccb99 100644 --- a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs +++ b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs @@ -313,7 +313,7 @@ impl<'a> BlueprintBuilder<'a> { // of used resources we built above if needed. let nexus_v4_ips = AvailableIterator::new( NEXUS_OPTE_IPV4_SUBNET - .iter() + .addr_iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), existing_nexus_v4_ips, ); @@ -578,7 +578,7 @@ impl<'a> BlueprintBuilder<'a> { // these are at known, fixed addresses relative to the AZ subnet // (which itself is a known-prefix parent subnet of the sled subnet). let dns_servers = - get_internal_dns_server_addresses(sled_subnet.net().network()); + get_internal_dns_server_addresses(sled_subnet.net().prefix()); // The list of boundary NTP servers is not necessarily stored // anywhere (unless there happens to be another internal NTP zone @@ -827,7 +827,7 @@ impl<'a> BlueprintBuilder<'a> { let sled_subnet = self.sled_resources(sled_id)?.subnet; let allocator = self.sled_ip_allocators.entry(sled_id).or_insert_with(|| { - let sled_subnet_addr = sled_subnet.net().network(); + let sled_subnet_addr = sled_subnet.net().prefix(); let minimum = sled_subnet_addr .saturating_add(u128::from(SLED_RESERVED_ADDRESSES)); let maximum = sled_subnet_addr diff --git a/nexus/src/app/allow_list.rs b/nexus/src/app/allow_list.rs index 6a3599f796..82f5df9a78 100644 --- a/nexus/src/app/allow_list.rs +++ b/nexus/src/app/allow_list.rs @@ -60,7 +60,7 @@ impl super::Nexus { any source to connect to user-facing services.", )); } - if entry.prefix() == 0 { + if entry.width() == 0 { return Err(Error::invalid_request( "Source IP allowlist entries may not have \ a netmask of /0.", diff --git a/nexus/src/app/sagas/vpc_create.rs b/nexus/src/app/sagas/vpc_create.rs index 4d3e5bd474..f195cacc54 100644 --- a/nexus/src/app/sagas/vpc_create.rs +++ b/nexus/src/app/sagas/vpc_create.rs @@ -291,7 +291,7 @@ async fn svc_create_subnet( // Allocate the first /64 sub-range from the requested or created // prefix. - let ipv6_block = oxnet::Ipv6Net::new(db_vpc.ipv6_prefix.network(), 64) + let ipv6_block = oxnet::Ipv6Net::new(db_vpc.ipv6_prefix.prefix(), 64) .map_err(|_| { external::Error::internal_error( "Failed to allocate default IPv6 subnet", diff --git a/nexus/src/app/vpc_subnet.rs b/nexus/src/app/vpc_subnet.rs index 9dbd617ae4..f081f351db 100644 --- a/nexus/src/app/vpc_subnet.rs +++ b/nexus/src/app/vpc_subnet.rs @@ -75,13 +75,13 @@ impl super::Nexus { let (.., authz_vpc, db_vpc) = vpc_lookup.fetch().await?; // Validate IPv4 range - if !params.ipv4_block.network().is_private() { + if !params.ipv4_block.prefix().is_private() { return Err(external::Error::invalid_request( "VPC Subnet IPv4 address ranges must be from a private range", )); } - if params.ipv4_block.prefix() < MIN_VPC_IPV4_SUBNET_PREFIX - || params.ipv4_block.prefix() + if params.ipv4_block.width() < MIN_VPC_IPV4_SUBNET_PREFIX + || params.ipv4_block.width() > self.tunables.max_vpc_ipv4_subnet_prefix { return Err(external::Error::invalid_request(&format!( diff --git a/nexus/test-utils/src/lib.rs b/nexus/test-utils/src/lib.rs index 3d0dfb0096..87ec64aa0b 100644 --- a/nexus/test-utils/src/lib.rs +++ b/nexus/test-utils/src/lib.rs @@ -671,7 +671,7 @@ impl<'a, N: NexusServer> ControlPlaneTestContextBuilder<'a, N> { nic: NetworkInterface { id: Uuid::new_v4(), ip: NEXUS_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 1) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 1) .unwrap() .into(), kind: NetworkInterfaceKind::Service { @@ -1012,7 +1012,7 @@ impl<'a, N: NexusServer> ControlPlaneTestContextBuilder<'a, N> { nic: NetworkInterface { id: Uuid::new_v4(), ip: DNS_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 1) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 1) .unwrap() .into(), kind: NetworkInterfaceKind::Service { diff --git a/nexus/tests/integration_tests/subnet_allocation.rs b/nexus/tests/integration_tests/subnet_allocation.rs index c445697d4e..5dd3f2e3dc 100644 --- a/nexus/tests/integration_tests/subnet_allocation.rs +++ b/nexus/tests/integration_tests/subnet_allocation.rs @@ -130,10 +130,12 @@ async fn test_subnet_allocation(cptestctx: &ControlPlaneTestContext) { // Create enough instances to fill the subnet. There are subnet.size() total // addresses, 6 of which are reserved. - let n_final_reserved_addresses = 1; - let n_reserved_addresses = - NUM_INITIAL_RESERVED_IP_ADDRESSES + n_final_reserved_addresses; - let subnet_size = subnet.size() as usize - n_reserved_addresses; + let subnet_size = match subnet.size() { + Some(n) => n - 1, + None => u32::MAX, + } as usize; + let subnet_size = subnet_size - NUM_INITIAL_RESERVED_IP_ADDRESSES; + // let subnet_size = subnet.size() as usize - n_reserved_addresses; for i in 0..subnet_size { create_instance_with( client, @@ -174,7 +176,7 @@ async fn test_subnet_allocation(cptestctx: &ControlPlaneTestContext) { network_interfaces.sort_by(|a, b| a.ip.cmp(&b.ip)); for (iface, addr) in network_interfaces .iter() - .zip(subnet.iter().skip(NUM_INITIAL_RESERVED_IP_ADDRESSES)) + .zip(subnet.addr_iter().skip(NUM_INITIAL_RESERVED_IP_ADDRESSES)) { assert_eq!( iface.ip, diff --git a/nexus/tests/integration_tests/vpc_subnets.rs b/nexus/tests/integration_tests/vpc_subnets.rs index 9314decd46..9bb806f208 100644 --- a/nexus/tests/integration_tests/vpc_subnets.rs +++ b/nexus/tests/integration_tests/vpc_subnets.rs @@ -162,8 +162,8 @@ async fn test_vpc_subnets(cptestctx: &ControlPlaneTestContext) { // Create a VPC Subnet. let ipv4_block = "10.0.0.0/24".parse().unwrap(); let other_ipv4_block = "172.31.0.0/16".parse().unwrap(); - // Create the first two available IPv6 address ranges. */ - let prefix = vpc.ipv6_prefix.network(); + // Create the first two available IPv6 address ranges. + let prefix = vpc.ipv6_prefix.prefix(); let ipv6_block = Ipv6Net::new(prefix, 64).unwrap(); let mut segments = prefix.segments(); segments[3] = 1; diff --git a/nexus/tests/integration_tests/vpcs.rs b/nexus/tests/integration_tests/vpcs.rs index 1844c79258..1ceebd8cff 100644 --- a/nexus/tests/integration_tests/vpcs.rs +++ b/nexus/tests/integration_tests/vpcs.rs @@ -100,7 +100,7 @@ async fn test_vpcs(cptestctx: &ControlPlaneTestContext) { assert_eq!(vpc.identity.description, "vpc description"); assert_eq!(vpc.dns_name, "abc"); assert_eq!( - vpc.ipv6_prefix.prefix(), + vpc.ipv6_prefix.width(), 48, "Expected a 48-bit ULA IPv6 address prefix" ); diff --git a/sled-agent/src/bootstrap/early_networking.rs b/sled-agent/src/bootstrap/early_networking.rs index 84891b6cbc..8727a01eae 100644 --- a/sled-agent/src/bootstrap/early_networking.rs +++ b/sled-agent/src/bootstrap/early_networking.rs @@ -516,11 +516,11 @@ impl<'a> EarlyNetworkSetup<'a> { .iter() .map(|x| match x { IpNet::V4(p) => Prefix::V4(Prefix4 { - length: p.prefix(), + length: p.width(), value: p.addr(), }), IpNet::V6(p) => Prefix::V6(Prefix6 { - length: p.prefix(), + length: p.width(), value: p.addr(), }), }) @@ -538,11 +538,11 @@ impl<'a> EarlyNetworkSetup<'a> { .iter() .map(|x| match x { IpNet::V4(p) => Prefix::V4(Prefix4 { - length: p.prefix(), + length: p.width(), value: p.addr(), }), IpNet::V6(p) => Prefix::V6(Prefix6 { - length: p.prefix(), + length: p.width(), value: p.addr(), }), }) diff --git a/sled-agent/src/bootstrap/server.rs b/sled-agent/src/bootstrap/server.rs index d4c17e20a6..369437d3aa 100644 --- a/sled-agent/src/bootstrap/server.rs +++ b/sled-agent/src/bootstrap/server.rs @@ -406,7 +406,7 @@ async fn start_sled_agent( ddmd_client.advertise_prefix(request.body.subnet); let az_prefix = - Ipv6Subnet::::new(request.body.subnet.net().network()); + Ipv6Subnet::::new(request.body.subnet.net().addr()); let addr = request.body.subnet.net().iter().nth(1).unwrap(); let dns_servers = Resolver::servers_from_subnet(az_prefix); ddmd_client.enable_stats( diff --git a/sled-agent/src/rack_setup/plan/service.rs b/sled-agent/src/rack_setup/plan/service.rs index 6eba6b58b9..a763d61923 100644 --- a/sled-agent/src/rack_setup/plan/service.rs +++ b/sled-agent/src/rack_setup/plan/service.rs @@ -960,14 +960,16 @@ impl ServicePortBuilder { let external_dns_ips = config.external_dns_ips.clone().into_iter(); let dns_v4_ips = Box::new( - DNS_OPTE_IPV4_SUBNET.iter().skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), + DNS_OPTE_IPV4_SUBNET + .addr_iter() + .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), ); let dns_v6_ips = Box::new( DNS_OPTE_IPV6_SUBNET.iter().skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), ); let nexus_v4_ips = Box::new( NEXUS_OPTE_IPV4_SUBNET - .iter() + .addr_iter() .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), ); let nexus_v6_ips = Box::new( @@ -976,7 +978,9 @@ impl ServicePortBuilder { .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), ); let ntp_v4_ips = Box::new( - NTP_OPTE_IPV4_SUBNET.iter().skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), + NTP_OPTE_IPV4_SUBNET + .addr_iter() + .skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), ); let ntp_v6_ips = Box::new( NTP_OPTE_IPV6_SUBNET.iter().skip(NUM_INITIAL_RESERVED_IP_ADDRESSES), diff --git a/sled-agent/src/services.rs b/sled-agent/src/services.rs index 3374328dfe..3363950c46 100644 --- a/sled-agent/src/services.rs +++ b/sled-agent/src/services.rs @@ -2711,7 +2711,7 @@ impl ServiceManager { // network address, without the mask. smfh.setprop( format!("config/techport{i}_prefix"), - prefix.net().network().to_string(), + prefix.net().addr(), )?; } smfh.setprop("config/pkt_source", pkt_source)?; diff --git a/sled-agent/src/sim/server.rs b/sled-agent/src/sim/server.rs index ebee0adc1f..e3ce4ad4e4 100644 --- a/sled-agent/src/sim/server.rs +++ b/sled-agent/src/sim/server.rs @@ -401,7 +401,7 @@ pub async fn run_standalone_server( kind: NetworkInterfaceKind::Service { id }, name: "nexus".parse().unwrap(), ip: NEXUS_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 1) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 1) .unwrap() .into(), mac: macs.next().unwrap(), @@ -444,7 +444,7 @@ pub async fn run_standalone_server( kind: NetworkInterfaceKind::Service { id }, name: "external-dns".parse().unwrap(), ip: DNS_OPTE_IPV4_SUBNET - .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES as u32 + 1) + .nth(NUM_INITIAL_RESERVED_IP_ADDRESSES + 1) .unwrap() .into(), mac: macs.next().unwrap(), From ed2e35c065f67904b67d71aa00036e120ca64c63 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 14:37:36 -0700 Subject: [PATCH 07/23] lint --- nexus/db-queries/src/db/datastore/rack.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/nexus/db-queries/src/db/datastore/rack.rs b/nexus/db-queries/src/db/datastore/rack.rs index e3f127891e..ebb5b7a362 100644 --- a/nexus/db-queries/src/db/datastore/rack.rs +++ b/nexus/db-queries/src/db/datastore/rack.rs @@ -1338,8 +1338,7 @@ mod test { name: "external-dns".parse().unwrap(), ip: external_dns_pip.into(), mac: macs.next().unwrap(), - subnet: IpNet::from(*DNS_OPTE_IPV4_SUBNET) - .into(), + subnet: IpNet::from(*DNS_OPTE_IPV4_SUBNET), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -1365,8 +1364,7 @@ mod test { name: "ntp1".parse().unwrap(), ip: ntp1_pip.into(), mac: macs.next().unwrap(), - subnet: IpNet::from(*NTP_OPTE_IPV4_SUBNET) - .into(), + subnet: IpNet::from(*NTP_OPTE_IPV4_SUBNET), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -1412,8 +1410,7 @@ mod test { mac: macs.next().unwrap(), subnet: IpNet::from( *NEXUS_OPTE_IPV4_SUBNET, - ) - .into(), + ), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -1439,8 +1436,7 @@ mod test { name: "ntp2".parse().unwrap(), ip: ntp2_pip.into(), mac: macs.next().unwrap(), - subnet: IpNet::from(*NTP_OPTE_IPV4_SUBNET) - .into(), + subnet: IpNet::from(*NTP_OPTE_IPV4_SUBNET), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -1663,8 +1659,7 @@ mod test { mac: macs.next().unwrap(), subnet: IpNet::from( *NEXUS_OPTE_IPV4_SUBNET, - ) - .into(), + ), vni: Vni::SERVICES_VNI, primary: true, slot: 0, From bacc59fe6f19c53d4c4ef0706e657646c26c24d6 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 14:37:41 -0700 Subject: [PATCH 08/23] update to github dep --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- workspace-hack/Cargo.toml | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e47365b0ce..2ece33d924 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5760,7 +5760,6 @@ dependencies = [ "aho-corasick", "anyhow", "base16ct", - "base64 0.22.1", "bit-set", "bit-vec", "bitflags 1.3.2", @@ -5836,6 +5835,7 @@ dependencies = [ "ring 0.17.8", "rustix", "schemars", + "scopeguard", "semver 1.0.22", "serde", "serde_json", @@ -5860,7 +5860,7 @@ dependencies = [ "trust-dns-proto", "unicode-bidi", "unicode-normalization", - "usdt 0.3.5", + "usdt 0.5.0", "usdt-impl 0.5.0", "uuid", "yasna", @@ -6301,6 +6301,7 @@ dependencies = [ [[package]] name = "oxnet" version = "0.1.0" +source = "git+https://github.com/oxidecomputer/oxnet?branch=main#1c5ef4dc3542f5bf544c74519d522b147bfeb8d0" dependencies = [ "ipnetwork", "schemars", diff --git a/Cargo.toml b/Cargo.toml index 1bf410e085..5f529a1749 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -288,7 +288,7 @@ omicron-certificates = { path = "certificates" } omicron-passwords = { path = "passwords" } omicron-workspace-hack = "0.1.0" oxlog = { path = "dev-tools/oxlog" } -oxnet = { path = "../oxnet", version = "0.1.0" } +oxnet = { git = "https://github.com/oxidecomputer/oxnet", branch = "main" } nexus-test-interface = { path = "nexus/test-interface" } nexus-test-utils-macros = { path = "nexus/test-utils-macros" } nexus-test-utils = { path = "nexus/test-utils" } diff --git a/workspace-hack/Cargo.toml b/workspace-hack/Cargo.toml index 4222d6141a..351cbaabd7 100644 --- a/workspace-hack/Cargo.toml +++ b/workspace-hack/Cargo.toml @@ -18,7 +18,6 @@ ahash = { version = "0.8.8" } aho-corasick = { version = "1.1.2" } anyhow = { version = "1.0.82", features = ["backtrace"] } base16ct = { version = "0.2.0", default-features = false, features = ["alloc"] } -base64 = { version = "0.22.0" } bit-set = { version = "0.5.3" } bit-vec = { version = "0.6.3" } bitflags-dff4ba8e3ae991db = { package = "bitflags", version = "1.3.2" } @@ -89,10 +88,11 @@ regex-automata = { version = "0.4.5", default-features = false, features = ["dfa regex-syntax = { version = "0.8.2" } reqwest = { version = "0.11.27", features = ["blocking", "cookies", "json", "rustls-tls", "stream"] } ring = { version = "0.17.8", features = ["std"] } -schemars = { version = "0.8.17", features = ["bytes", "chrono", "uuid1"] } +schemars = { version = "0.8.19", features = ["bytes", "chrono", "uuid1"] } +scopeguard = { version = "1.2.0" } semver = { version = "1.0.22", features = ["serde"] } -serde = { version = "1.0.199", features = ["alloc", "derive", "rc"] } -serde_json = { version = "1.0.116", features = ["raw_value", "unbounded_depth"] } +serde = { version = "1.0.202", features = ["alloc", "derive", "rc"] } +serde_json = { version = "1.0.117", features = ["raw_value", "unbounded_depth"] } sha2 = { version = "0.10.8", features = ["oid"] } similar = { version = "2.4.0", features = ["inline", "unicode"] } slog = { version = "2.7.0", features = ["dynamic-keys", "max_level_trace", "release_max_level_debug", "release_max_level_trace"] } @@ -101,7 +101,7 @@ spin = { version = "0.9.8" } string_cache = { version = "0.8.7" } subtle = { version = "2.5.0" } syn-dff4ba8e3ae991db = { package = "syn", version = "1.0.109", features = ["extra-traits", "fold", "full", "visit"] } -syn-f595c2ba2a3f28df = { package = "syn", version = "2.0.60", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] } +syn-f595c2ba2a3f28df = { package = "syn", version = "2.0.64", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] } time = { version = "0.3.34", features = ["formatting", "local-offset", "macros", "parsing"] } tokio = { version = "1.37.0", features = ["full", "test-util"] } tokio-postgres = { version = "0.7.10", features = ["with-chrono-0_4", "with-serde_json-1", "with-uuid-1"] } @@ -113,7 +113,7 @@ tracing = { version = "0.1.40", features = ["log"] } trust-dns-proto = { version = "0.22.0" } unicode-bidi = { version = "0.3.15" } unicode-normalization = { version = "0.1.22" } -usdt = { version = "0.3.5" } +usdt = { version = "0.5.0" } usdt-impl = { version = "0.5.0", default-features = false, features = ["asm", "des"] } uuid = { version = "1.8.0", features = ["serde", "v4"] } yasna = { version = "0.5.2", features = ["bit-vec", "num-bigint", "std", "time"] } @@ -126,7 +126,6 @@ ahash = { version = "0.8.8" } aho-corasick = { version = "1.1.2" } anyhow = { version = "1.0.82", features = ["backtrace"] } base16ct = { version = "0.2.0", default-features = false, features = ["alloc"] } -base64 = { version = "0.22.0" } bit-set = { version = "0.5.3" } bit-vec = { version = "0.6.3" } bitflags-dff4ba8e3ae991db = { package = "bitflags", version = "1.3.2" } @@ -197,10 +196,11 @@ regex-automata = { version = "0.4.5", default-features = false, features = ["dfa regex-syntax = { version = "0.8.2" } reqwest = { version = "0.11.27", features = ["blocking", "cookies", "json", "rustls-tls", "stream"] } ring = { version = "0.17.8", features = ["std"] } -schemars = { version = "0.8.17", features = ["bytes", "chrono", "uuid1"] } +schemars = { version = "0.8.19", features = ["bytes", "chrono", "uuid1"] } +scopeguard = { version = "1.2.0" } semver = { version = "1.0.22", features = ["serde"] } -serde = { version = "1.0.199", features = ["alloc", "derive", "rc"] } -serde_json = { version = "1.0.116", features = ["raw_value", "unbounded_depth"] } +serde = { version = "1.0.202", features = ["alloc", "derive", "rc"] } +serde_json = { version = "1.0.117", features = ["raw_value", "unbounded_depth"] } sha2 = { version = "0.10.8", features = ["oid"] } similar = { version = "2.4.0", features = ["inline", "unicode"] } slog = { version = "2.7.0", features = ["dynamic-keys", "max_level_trace", "release_max_level_debug", "release_max_level_trace"] } @@ -209,7 +209,7 @@ spin = { version = "0.9.8" } string_cache = { version = "0.8.7" } subtle = { version = "2.5.0" } syn-dff4ba8e3ae991db = { package = "syn", version = "1.0.109", features = ["extra-traits", "fold", "full", "visit"] } -syn-f595c2ba2a3f28df = { package = "syn", version = "2.0.60", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] } +syn-f595c2ba2a3f28df = { package = "syn", version = "2.0.64", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] } time = { version = "0.3.34", features = ["formatting", "local-offset", "macros", "parsing"] } time-macros = { version = "0.2.17", default-features = false, features = ["formatting", "parsing"] } tokio = { version = "1.37.0", features = ["full", "test-util"] } @@ -222,7 +222,7 @@ tracing = { version = "0.1.40", features = ["log"] } trust-dns-proto = { version = "0.22.0" } unicode-bidi = { version = "0.3.15" } unicode-normalization = { version = "0.1.22" } -usdt = { version = "0.3.5" } +usdt = { version = "0.5.0" } usdt-impl = { version = "0.5.0", default-features = false, features = ["asm", "des"] } uuid = { version = "1.8.0", features = ["serde", "v4"] } yasna = { version = "0.5.2", features = ["bit-vec", "num-bigint", "std", "time"] } From 656697654970fead5e31bb6c3dda4ad27c1e629e Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 15:05:09 -0700 Subject: [PATCH 09/23] update --- Cargo.lock | 4 ++++ Cargo.toml | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ffd6653284..b4b09f764c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7044,6 +7044,7 @@ dependencies = [ [[package]] name = "progenitor" version = "0.7.0" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#c59c6d64ed2a206bbbc9949abd3457bc0e3810e2" dependencies = [ "progenitor-client", "progenitor-impl", @@ -7054,6 +7055,7 @@ dependencies = [ [[package]] name = "progenitor-client" version = "0.7.0" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#c59c6d64ed2a206bbbc9949abd3457bc0e3810e2" dependencies = [ "bytes", "futures-core", @@ -7067,6 +7069,7 @@ dependencies = [ [[package]] name = "progenitor-impl" version = "0.7.0" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#c59c6d64ed2a206bbbc9949abd3457bc0e3810e2" dependencies = [ "getopts", "heck 0.5.0", @@ -7088,6 +7091,7 @@ dependencies = [ [[package]] name = "progenitor-macro" version = "0.7.0" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#c59c6d64ed2a206bbbc9949abd3457bc0e3810e2" dependencies = [ "openapiv3", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 0a9cd638d2..1ab6ded16d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -682,9 +682,9 @@ dropshot = { path = "../dropshot/dropshot" } # # Local client generation during development. # -[patch."https://github.com/oxidecomputer/progenitor"] -progenitor = { path = "../progenitor/progenitor" } -progenitor-client = { path = "../progenitor/progenitor-client" } +#[patch."https://github.com/oxidecomputer/progenitor"] +#progenitor = { path = "../progenitor/progenitor" } +#progenitor-client = { path = "../progenitor/progenitor-client" } #[patch."https://github.com/oxidecomputer/typify"] #typify = { path = "../typify/typify" } From acbbb3801edf09d6508f38d62393163830002b38 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 15:43:30 -0700 Subject: [PATCH 10/23] updates --- Cargo.lock | 12 +++++++----- Cargo.toml | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b4b09f764c..e157cac7d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2026,6 +2026,7 @@ dependencies = [ [[package]] name = "dropshot" version = "0.10.2-dev" +source = "git+https://github.com/oxidecomputer/dropshot?branch=main#0cd0e828d096578392b6a5524334d44fd10ef6da" dependencies = [ "async-stream", "async-trait", @@ -2071,6 +2072,7 @@ dependencies = [ [[package]] name = "dropshot_endpoint" version = "0.10.2-dev" +source = "git+https://github.com/oxidecomputer/dropshot?branch=main#0cd0e828d096578392b6a5524334d44fd10ef6da" dependencies = [ "proc-macro2", "quote", @@ -4022,7 +4024,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.5", + "windows-targets 0.48.5", ] [[package]] @@ -8217,9 +8219,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6e7ed6919cb46507fb01ff1654309219f62b4d603822501b0b80d42f6f21ef" +checksum = "b0218ceea14babe24a4a5836f86ade86c1effbc198164e619194cb5069187e29" dependencies = [ "bytes", "chrono", @@ -8232,9 +8234,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185f2b7aa7e02d418e453790dde16890256bbd2bcd04b7dc5348811052b53f49" +checksum = "3ed5a1ccce8ff962e31a165d41f6e2a2dd1245099dc4d594f5574a86cd90f4d3" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 1ab6ded16d..4e930a5c58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -663,8 +663,8 @@ opt-level = 3 # It's common during development to use a local copy of various complex # dependencies. If you want to use those, uncomment one of these blocks. # -[patch."https://github.com/oxidecomputer/dropshot"] -dropshot = { path = "../dropshot/dropshot" } +#[patch."https://github.com/oxidecomputer/dropshot"] +#dropshot = { path = "../dropshot/dropshot" } #[patch.crates-io] #steno = { path = "../steno" } #[patch."https://github.com/oxidecomputer/propolis"] From 0ccf1691f7d3b9628fb380a0d23ad9c7efa4671c Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 15:52:19 -0700 Subject: [PATCH 11/23] hakari --- workspace-hack/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workspace-hack/Cargo.toml b/workspace-hack/Cargo.toml index d8c9e7c634..3b5e1917d0 100644 --- a/workspace-hack/Cargo.toml +++ b/workspace-hack/Cargo.toml @@ -89,7 +89,7 @@ regex-automata = { version = "0.4.6", default-features = false, features = ["dfa regex-syntax = { version = "0.8.3" } reqwest = { version = "0.11.27", features = ["blocking", "cookies", "json", "rustls-tls", "stream"] } ring = { version = "0.17.8", features = ["std"] } -schemars = { version = "0.8.19", features = ["bytes", "chrono", "uuid1"] } +schemars = { version = "0.8.20", features = ["bytes", "chrono", "uuid1"] } scopeguard = { version = "1.2.0" } semver = { version = "1.0.23", features = ["serde"] } serde = { version = "1.0.202", features = ["alloc", "derive", "rc"] } @@ -194,7 +194,7 @@ regex-automata = { version = "0.4.6", default-features = false, features = ["dfa regex-syntax = { version = "0.8.3" } reqwest = { version = "0.11.27", features = ["blocking", "cookies", "json", "rustls-tls", "stream"] } ring = { version = "0.17.8", features = ["std"] } -schemars = { version = "0.8.19", features = ["bytes", "chrono", "uuid1"] } +schemars = { version = "0.8.20", features = ["bytes", "chrono", "uuid1"] } scopeguard = { version = "1.2.0" } semver = { version = "1.0.23", features = ["serde"] } serde = { version = "1.0.202", features = ["alloc", "derive", "rc"] } From 2724da86f6fe866c977944dad6b886811a5883c3 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 16:46:35 -0700 Subject: [PATCH 12/23] lint --- nexus/db-queries/src/db/datastore/rack.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/nexus/db-queries/src/db/datastore/rack.rs b/nexus/db-queries/src/db/datastore/rack.rs index 39b8704dbc..b8275b56d4 100644 --- a/nexus/db-queries/src/db/datastore/rack.rs +++ b/nexus/db-queries/src/db/datastore/rack.rs @@ -1970,8 +1970,7 @@ mod test { name: "nexus".parse().unwrap(), ip: nexus_pip.into(), mac: macs.next().unwrap(), - subnet: IpNet::from(*NEXUS_OPTE_IPV4_SUBNET) - .into(), + subnet: IpNet::from(*NEXUS_OPTE_IPV4_SUBNET), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -2073,8 +2072,7 @@ mod test { name: "external-dns".parse().unwrap(), ip: external_dns_pip.into(), mac: macs.next().unwrap(), - subnet: IpNet::from(*DNS_OPTE_IPV4_SUBNET) - .into(), + subnet: IpNet::from(*DNS_OPTE_IPV4_SUBNET), vni: Vni::SERVICES_VNI, primary: true, slot: 0, @@ -2105,8 +2103,7 @@ mod test { mac: macs.next().unwrap(), subnet: IpNet::from( *NEXUS_OPTE_IPV4_SUBNET, - ) - .into(), + ), vni: Vni::SERVICES_VNI, primary: true, slot: 0, From 2bca9ef612d8c9e46f49c0d9b6800457ace1f932 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 17:15:07 -0700 Subject: [PATCH 13/23] illumos build --- sled-agent/src/services.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sled-agent/src/services.rs b/sled-agent/src/services.rs index 3363950c46..ff10d4aed7 100644 --- a/sled-agent/src/services.rs +++ b/sled-agent/src/services.rs @@ -5066,9 +5066,9 @@ mod test { fn test_bootstrap_addr_to_techport_prefixes() { let ba: Ipv6Addr = "fdb0:1122:3344:5566::".parse().unwrap(); let prefixes = ServiceManager::bootstrap_addr_to_techport_prefixes(&ba); - assert!(prefixes.iter().all(|p| p.net().prefix() == 64)); - let prefix0 = prefixes[0].net().network(); - let prefix1 = prefixes[1].net().network(); + assert!(prefixes.iter().all(|p| p.net().width() == 64)); + let prefix0 = prefixes[0].net().prefix(); + let prefix1 = prefixes[1].net().prefix(); assert_eq!(prefix0.segments()[1..], ba.segments()[1..]); assert_eq!(prefix1.segments()[1..], ba.segments()[1..]); assert_eq!(prefix0.segments()[0], 0xfdb1); From 3dc4dd1cfc2398ab8b6b7710765cb43acb4f9557 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 19:48:24 -0700 Subject: [PATCH 14/23] nits from review --- common/src/address.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/common/src/address.rs b/common/src/address.rs index 900fa76079..c36dee7cd0 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -193,8 +193,6 @@ pub struct Ipv6Subnet { impl Ipv6Subnet { pub fn new(addr: Ipv6Addr) -> Self { - // TODO should Ipv6Net either validate that the address is canonical or - // mask it appropriately? i.e. rendering these steps unnecessary? // Create a network with the compile-time prefix length. let net = Ipv6Net::new(addr, N).unwrap(); // Ensure the address is set to within-prefix only components. @@ -253,7 +251,7 @@ impl DnsSubnet { /// This is the first address within the subnet. pub fn dns_address(&self) -> Ipv6Net { Ipv6Net::new( - self.subnet.net().iter().nth(DNS_ADDRESS_INDEX).unwrap(), + self.subnet.net().nth(DNS_ADDRESS_INDEX as u128).unwrap(), SLED_PREFIX, ) .unwrap() @@ -266,7 +264,7 @@ impl DnsSubnet { /// This is the second address within the subnet. pub fn gz_address(&self) -> Ipv6Net { Ipv6Net::new( - self.subnet.net().iter().nth(GZ_ADDRESS_INDEX).unwrap(), + self.subnet.net().nth(GZ_ADDRESS_INDEX as u128).unwrap(), SLED_PREFIX, ) .unwrap() @@ -320,7 +318,7 @@ const SWITCH_ZONE_ADDRESS_INDEX: usize = 2; /// This address will come from the first address of the [`SLED_PREFIX`] subnet. pub fn get_sled_address(sled_subnet: Ipv6Subnet) -> SocketAddrV6 { let sled_agent_ip = - sled_subnet.net().iter().nth(SLED_AGENT_ADDRESS_INDEX).unwrap(); + sled_subnet.net().nth(SLED_AGENT_ADDRESS_INDEX as u128).unwrap(); SocketAddrV6::new(sled_agent_ip, SLED_AGENT_PORT, 0, 0) } @@ -330,7 +328,7 @@ pub fn get_sled_address(sled_subnet: Ipv6Subnet) -> SocketAddrV6 { pub fn get_switch_zone_address( sled_subnet: Ipv6Subnet, ) -> Ipv6Addr { - sled_subnet.net().iter().nth(SWITCH_ZONE_ADDRESS_INDEX).unwrap() + sled_subnet.net().nth(SWITCH_ZONE_ADDRESS_INDEX as u128).unwrap() } /// Returns a sled subnet within a rack subnet. From 92f0d51912fa6190e9291276016da9f7df30be55 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 19:48:36 -0700 Subject: [PATCH 15/23] openapi fixtures --- openapi/bootstrap-agent.json | 17 ++++++++++++++++- openapi/nexus-internal.json | 17 ++++++++++++++++- openapi/nexus.json | 17 ++++++++++++++++- openapi/sled-agent.json | 17 ++++++++++++++++- openapi/wicketd.json | 17 ++++++++++++++++- 5 files changed, 80 insertions(+), 5 deletions(-) diff --git a/openapi/bootstrap-agent.json b/openapi/bootstrap-agent.json index f177c27f55..ddfc1e91f8 100644 --- a/openapi/bootstrap-agent.json +++ b/openapi/bootstrap-agent.json @@ -620,6 +620,11 @@ ] }, "IpNet": { + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::IpNet", + "version": "0.1.0" + }, "oneOf": [ { "title": "v4", @@ -683,7 +688,12 @@ "Ipv4Net": { "example": "192.168.1.0/24", "title": "An IPv4 subnet", - "description": "An IPv4 subnet, including prefix and subnet mask", + "description": "An IPv4 subnet, including prefix and prefix length", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv4Net", + "version": "0.1.0" + }, "type": "string", "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$" }, @@ -714,6 +724,11 @@ "example": "fd12:3456::/64", "title": "An IPv6 subnet", "description": "An IPv6 subnet, including prefix and subnet mask", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv6Net", + "version": "0.1.0" + }, "type": "string", "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" }, diff --git a/openapi/nexus-internal.json b/openapi/nexus-internal.json index c7d476994d..ad109a18fa 100644 --- a/openapi/nexus-internal.json +++ b/openapi/nexus-internal.json @@ -3174,6 +3174,11 @@ ] }, "IpNet": { + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::IpNet", + "version": "0.1.0" + }, "oneOf": [ { "title": "v4", @@ -3284,7 +3289,12 @@ "Ipv4Net": { "example": "192.168.1.0/24", "title": "An IPv4 subnet", - "description": "An IPv4 subnet, including prefix and subnet mask", + "description": "An IPv4 subnet, including prefix and prefix length", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv4Net", + "version": "0.1.0" + }, "type": "string", "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$" }, @@ -3315,6 +3325,11 @@ "example": "fd12:3456::/64", "title": "An IPv6 subnet", "description": "An IPv6 subnet, including prefix and subnet mask", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv6Net", + "version": "0.1.0" + }, "type": "string", "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" }, diff --git a/openapi/nexus.json b/openapi/nexus.json index 2bf6f0a6ff..a0789aecde 100644 --- a/openapi/nexus.json +++ b/openapi/nexus.json @@ -14314,6 +14314,11 @@ ] }, "IpNet": { + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::IpNet", + "version": "0.1.0" + }, "oneOf": [ { "title": "v4", @@ -14595,7 +14600,12 @@ "Ipv4Net": { "example": "192.168.1.0/24", "title": "An IPv4 subnet", - "description": "An IPv4 subnet, including prefix and subnet mask", + "description": "An IPv4 subnet, including prefix and prefix length", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv4Net", + "version": "0.1.0" + }, "type": "string", "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$" }, @@ -14642,6 +14652,11 @@ "example": "fd12:3456::/64", "title": "An IPv6 subnet", "description": "An IPv6 subnet, including prefix and subnet mask", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv6Net", + "version": "0.1.0" + }, "type": "string", "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" }, diff --git a/openapi/sled-agent.json b/openapi/sled-agent.json index 7a951a6d15..87fb00f261 100644 --- a/openapi/sled-agent.json +++ b/openapi/sled-agent.json @@ -3388,6 +3388,11 @@ ] }, "IpNet": { + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::IpNet", + "version": "0.1.0" + }, "oneOf": [ { "title": "v4", @@ -3431,7 +3436,12 @@ "Ipv4Net": { "example": "192.168.1.0/24", "title": "An IPv4 subnet", - "description": "An IPv4 subnet, including prefix and subnet mask", + "description": "An IPv4 subnet, including prefix and prefix length", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv4Net", + "version": "0.1.0" + }, "type": "string", "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$" }, @@ -3444,6 +3454,11 @@ "example": "fd12:3456::/64", "title": "An IPv6 subnet", "description": "An IPv6 subnet, including prefix and subnet mask", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv6Net", + "version": "0.1.0" + }, "type": "string", "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" }, diff --git a/openapi/wicketd.json b/openapi/wicketd.json index cb06c0cadf..762fbfade0 100644 --- a/openapi/wicketd.json +++ b/openapi/wicketd.json @@ -1666,6 +1666,11 @@ ] }, "IpNet": { + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::IpNet", + "version": "0.1.0" + }, "oneOf": [ { "title": "v4", @@ -1729,7 +1734,12 @@ "Ipv4Net": { "example": "192.168.1.0/24", "title": "An IPv4 subnet", - "description": "An IPv4 subnet, including prefix and subnet mask", + "description": "An IPv4 subnet, including prefix and prefix length", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv4Net", + "version": "0.1.0" + }, "type": "string", "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$" }, @@ -1760,6 +1770,11 @@ "example": "fd12:3456::/64", "title": "An IPv6 subnet", "description": "An IPv6 subnet, including prefix and subnet mask", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv6Net", + "version": "0.1.0" + }, "type": "string", "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" }, From 0541842329016cd90f475b3324bd411cc5075be7 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 21:13:21 -0700 Subject: [PATCH 16/23] more fixtures --- common/src/api/internal/shared.rs | 2 +- schema/deployment-config.json | 7 ++++++- schema/rss-service-plan-v3.json | 23 +++++++++++++++++++---- schema/start-sled-agent-request.json | 7 ++++++- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/common/src/api/internal/shared.rs b/common/src/api/internal/shared.rs index 6e12d35c53..b0d3232eed 100644 --- a/common/src/api/internal/shared.rs +++ b/common/src/api/internal/shared.rs @@ -601,7 +601,7 @@ mod tests { #[test] fn test_deserialize_allowed_source_ips() { let parsed: AllowedSourceIps = serde_json::from_str( - r#"{"allow":"list","ips":["127.0.0.1","10.0.0.0/24","fd00::1/64"]}"#, + r#"{"allow":"list","ips":["127.0.0.1/32","10.0.0.0/24","fd00::1/64"]}"#, ) .unwrap(); assert_eq!( diff --git a/schema/deployment-config.json b/schema/deployment-config.json index 9fa4ba2159..2df5c64a88 100644 --- a/schema/deployment-config.json +++ b/schema/deployment-config.json @@ -132,7 +132,12 @@ "fd12:3456::/64" ], "type": "string", - "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" + "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv6Net", + "version": "0.1.0" + } }, "Ipv6Subnet": { "description": "Wraps an [`Ipv6Network`] with a compile-time prefix length.", diff --git a/schema/rss-service-plan-v3.json b/schema/rss-service-plan-v3.json index bab3e916ba..d1540ca351 100644 --- a/schema/rss-service-plan-v3.json +++ b/schema/rss-service-plan-v3.json @@ -171,16 +171,26 @@ } ] } - ] + ], + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::IpNet", + "version": "0.1.0" + } }, "Ipv4Net": { "title": "An IPv4 subnet", - "description": "An IPv4 subnet, including prefix and subnet mask", + "description": "An IPv4 subnet, including prefix and prefix length", "examples": [ "192.168.1.0/24" ], "type": "string", - "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$" + "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv4Net", + "version": "0.1.0" + } }, "Ipv6Net": { "title": "An IPv6 subnet", @@ -189,7 +199,12 @@ "fd12:3456::/64" ], "type": "string", - "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" + "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv6Net", + "version": "0.1.0" + } }, "MacAddr": { "title": "A MAC address", diff --git a/schema/start-sled-agent-request.json b/schema/start-sled-agent-request.json index 7a7745617c..9b97be9a00 100644 --- a/schema/start-sled-agent-request.json +++ b/schema/start-sled-agent-request.json @@ -32,7 +32,12 @@ "fd12:3456::/64" ], "type": "string", - "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" + "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv6Net", + "version": "0.1.0" + } }, "Ipv6Subnet": { "description": "Wraps an [`Ipv6Network`] with a compile-time prefix length.", From 22ed4f0ae9c89c346a0e6c1abee9dbeb5826e377 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 21:57:50 -0700 Subject: [PATCH 17/23] update fixture and oxnet for iter fix --- Cargo.lock | 2 +- .../tests/output/planner_nonprovisionable_2_2a.txt | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e157cac7d1..01f6e8a1a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6343,7 +6343,7 @@ dependencies = [ [[package]] name = "oxnet" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/oxnet?branch=main#1c5ef4dc3542f5bf544c74519d522b147bfeb8d0" +source = "git+https://github.com/oxidecomputer/oxnet?branch=main#42b4d3c77c7f5f2636cd6c4bbf37ac3eada047e0" dependencies = [ "ipnetwork", "schemars", diff --git a/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_2_2a.txt b/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_2_2a.txt index 648c082c0f..fa61fa2758 100644 --- a/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_2_2a.txt +++ b/nexus/reconfigurator/planning/tests/output/planner_nonprovisionable_2_2a.txt @@ -196,12 +196,10 @@ ERRORS: ), ), subnet: V4( - Ipv4Net( - Ipv4Network { - addr: 172.30.2.0, - prefix: 24, - }, - ), + Ipv4Net { + addr: 172.30.2.0, + width: 24, + }, ), vni: Vni( 100, From 0b8620cf51a544cd3e8be3596135f2789f5d8382 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Wed, 22 May 2024 22:48:43 -0700 Subject: [PATCH 18/23] last fixtures? --- schema/all-zone-requests.json | 23 +++++++++++++++++++---- schema/rss-sled-plan.json | 23 +++++++++++++++++++---- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/schema/all-zone-requests.json b/schema/all-zone-requests.json index 7fe9b139eb..fde6ee18a4 100644 --- a/schema/all-zone-requests.json +++ b/schema/all-zone-requests.json @@ -173,16 +173,26 @@ } ] } - ] + ], + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::IpNet", + "version": "0.1.0" + } }, "Ipv4Net": { "title": "An IPv4 subnet", - "description": "An IPv4 subnet, including prefix and subnet mask", + "description": "An IPv4 subnet, including prefix and prefix length", "examples": [ "192.168.1.0/24" ], "type": "string", - "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$" + "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv4Net", + "version": "0.1.0" + } }, "Ipv6Net": { "title": "An IPv6 subnet", @@ -191,7 +201,12 @@ "fd12:3456::/64" ], "type": "string", - "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" + "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv6Net", + "version": "0.1.0" + } }, "MacAddr": { "title": "A MAC address", diff --git a/schema/rss-sled-plan.json b/schema/rss-sled-plan.json index 95ca5b90ba..2dbd5f04b0 100644 --- a/schema/rss-sled-plan.json +++ b/schema/rss-sled-plan.json @@ -493,7 +493,12 @@ } ] } - ] + ], + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::IpNet", + "version": "0.1.0" + } }, "IpNetwork": { "oneOf": [ @@ -538,12 +543,17 @@ }, "Ipv4Net": { "title": "An IPv4 subnet", - "description": "An IPv4 subnet, including prefix and subnet mask", + "description": "An IPv4 subnet, including prefix and prefix length", "examples": [ "192.168.1.0/24" ], "type": "string", - "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$" + "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv4Net", + "version": "0.1.0" + } }, "Ipv4Network": { "type": "string", @@ -575,7 +585,12 @@ "fd12:3456::/64" ], "type": "string", - "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" + "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv6Net", + "version": "0.1.0" + } }, "Ipv6Network": { "type": "string", From 4024b66c0dc880b6001c2ff7d28c78305c50960f Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Thu, 23 May 2024 06:21:47 -0700 Subject: [PATCH 19/23] really last fixture for sure this time --- schema/all-zones-requests.json | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/schema/all-zones-requests.json b/schema/all-zones-requests.json index bb4dba2520..526e41376f 100644 --- a/schema/all-zones-requests.json +++ b/schema/all-zones-requests.json @@ -57,16 +57,26 @@ } ] } - ] + ], + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::IpNet", + "version": "0.1.0" + } }, "Ipv4Net": { "title": "An IPv4 subnet", - "description": "An IPv4 subnet, including prefix and subnet mask", + "description": "An IPv4 subnet, including prefix and prefix length", "examples": [ "192.168.1.0/24" ], "type": "string", - "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$" + "pattern": "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|1[0-9]|2[0-9]|3[0-2])$", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv4Net", + "version": "0.1.0" + } }, "Ipv6Net": { "title": "An IPv6 subnet", @@ -75,7 +85,12 @@ "fd12:3456::/64" ], "type": "string", - "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" + "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$", + "x-rust-type": { + "crate": "oxnet", + "path": "oxnet::Ipv6Net", + "version": "0.1.0" + } }, "MacAddr": { "title": "A MAC address", From 98bebdc223d8fa974801aedb488890e9942a0f87 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Thu, 23 May 2024 10:12:56 -0700 Subject: [PATCH 20/23] self-review nits --- common/src/address.rs | 4 +- common/src/api/external/mod.rs | 50 ------------------- nexus/src/app/instance_network.rs | 5 +- .../integration_tests/subnet_allocation.rs | 9 ++-- 4 files changed, 7 insertions(+), 61 deletions(-) diff --git a/common/src/address.rs b/common/src/address.rs index c36dee7cd0..c0aeb1a70f 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -184,7 +184,7 @@ pub const CP_SERVICES_RESERVED_ADDRESSES: u16 = 0xFFFF; // to assume that addresses in this subnet are available. pub const SLED_RESERVED_ADDRESSES: u16 = 32; -/// Wraps an [`Ipv6Network`] with a compile-time prefix length. +/// Wraps an [`Ipv6Net`] with a compile-time prefix length. #[derive(Debug, Clone, Copy, JsonSchema, Serialize, Hash, PartialEq, Eq)] #[schemars(rename = "Ipv6Subnet")] pub struct Ipv6Subnet { @@ -245,7 +245,6 @@ pub struct DnsSubnet { } impl DnsSubnet { - // TODO why are we returning a subnet? /// Returns the DNS server address within the subnet. /// /// This is the first address within the subnet. @@ -257,7 +256,6 @@ impl DnsSubnet { .unwrap() } - // TODO why are we returning a subnet? /// Returns the address which the Global Zone should create /// to be able to contact the DNS server. /// diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index 0f4773580c..9454a20efa 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -3433,56 +3433,6 @@ mod test { assert!("hash:super_random".parse::().is_err()); } - // #[test] - // fn test_ipnet_first_last_address() { - // use oxnet::IpNet; - // use std::net::IpAddr; - // use std::net::Ipv4Addr; - // use std::net::Ipv6Addr; - - // let net: IpNet = "fd00::/128".parse().unwrap(); - // assert_eq!( - // net.first_address(), - // IpAddr::from(Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 0)), - // ); - // assert_eq!( - // net.last_address(), - // IpAddr::from(Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 0)), - // ); - - // let net: IpNet = "fd00::/64".parse().unwrap(); - // assert_eq!( - // net.first_address(), - // IpAddr::from(Ipv6Addr::new(0xfd00, 0, 0, 0, 0, 0, 0, 0)), - // ); - // assert_eq!( - // net.last_address(), - // IpAddr::from(Ipv6Addr::new( - // 0xfd00, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff - // )), - // ); - - // let net: IpNet = "10.0.0.0/16".parse().unwrap(); - // assert_eq!( - // net.first_address(), - // IpAddr::from(Ipv4Addr::new(10, 0, 0, 0)), - // ); - // assert_eq!( - // net.last_address(), - // IpAddr::from(Ipv4Addr::new(10, 0, 255, 255)), - // ); - - // let net: IpNet = "10.0.0.0/32".parse().unwrap(); - // assert_eq!( - // net.first_address(), - // IpAddr::from(Ipv4Addr::new(10, 0, 0, 0)), - // ); - // assert_eq!( - // net.last_address(), - // IpAddr::from(Ipv4Addr::new(10, 0, 0, 0)), - // ); - // } - #[test] fn test_macaddr() { use super::MacAddr; diff --git a/nexus/src/app/instance_network.rs b/nexus/src/app/instance_network.rs index aab4d275cd..3c607bae78 100644 --- a/nexus/src/app/instance_network.rs +++ b/nexus/src/app/instance_network.rs @@ -510,7 +510,7 @@ pub(crate) async fn instance_ensure_dpd_config( )); } - let sled_address = Ipv6Net::new(*sled_ip_address.ip(), 128).unwrap(); + let sled_address = Ipv6Net::host_net(*sled_ip_address.ip()); // If all of our IPs are attached or are guaranteed to be owned // by the saga calling this fn, then we need to disregard and @@ -651,7 +651,7 @@ pub(crate) async fn probe_ensure_dpd_config( } } - let sled_address = Ipv6Net::new(sled_ip_address, 128).unwrap(); + let sled_address = Ipv6Net::host_net(sled_ip_address); for target_ip in ips .iter() @@ -1009,7 +1009,6 @@ async fn ensure_nat_entry( match target_ip.ip { IpNetwork::V4(v4net) => { let nat_entry = Ipv4NatValues { - // TODO could simplify this conversion? external_address: Ipv4Net::from(v4net).into(), first_port: target_ip.first_port, last_port: target_ip.last_port, diff --git a/nexus/tests/integration_tests/subnet_allocation.rs b/nexus/tests/integration_tests/subnet_allocation.rs index 60a5ccced4..794c769da4 100644 --- a/nexus/tests/integration_tests/subnet_allocation.rs +++ b/nexus/tests/integration_tests/subnet_allocation.rs @@ -132,14 +132,13 @@ async fn test_subnet_allocation(cptestctx: &ControlPlaneTestContext) { }, ]); - // Create enough instances to fill the subnet. There are subnet.size() total - // addresses, 6 of which are reserved. - let subnet_size = match subnet.size() { + // Create enough instances to fill the subnet. There are subnet.size() + // total addresses, 6 of which are reserved. + let subnet_size_minus_1 = match subnet.size() { Some(n) => n - 1, None => u32::MAX, } as usize; - let subnet_size = subnet_size - NUM_INITIAL_RESERVED_IP_ADDRESSES; - // let subnet_size = subnet.size() as usize - n_reserved_addresses; + let subnet_size = subnet_size_minus_1 - NUM_INITIAL_RESERVED_IP_ADDRESSES; for i in 0..subnet_size { create_instance_with( client, From 0d320e3d2feec9094c24e6e50ccf36ad757dc7db Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Thu, 23 May 2024 11:00:55 -0700 Subject: [PATCH 21/23] fixtures! --- openapi/sled-agent.json | 2 +- schema/deployment-config.json | 2 +- schema/rss-sled-plan.json | 2 +- schema/start-sled-agent-request.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openapi/sled-agent.json b/openapi/sled-agent.json index 87fb00f261..763a67910f 100644 --- a/openapi/sled-agent.json +++ b/openapi/sled-agent.json @@ -3468,7 +3468,7 @@ "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\")[/](12[0-8]|1[0-1][0-9]|[0-9]?[0-9])$" }, "Ipv6Subnet": { - "description": "Wraps an [`Ipv6Network`] with a compile-time prefix length.", + "description": "Wraps an [`Ipv6Net`] with a compile-time prefix length.", "type": "object", "properties": { "net": { diff --git a/schema/deployment-config.json b/schema/deployment-config.json index 2df5c64a88..7b737c52b2 100644 --- a/schema/deployment-config.json +++ b/schema/deployment-config.json @@ -140,7 +140,7 @@ } }, "Ipv6Subnet": { - "description": "Wraps an [`Ipv6Network`] with a compile-time prefix length.", + "description": "Wraps an [`Ipv6Net`] with a compile-time prefix length.", "type": "object", "required": [ "net" diff --git a/schema/rss-sled-plan.json b/schema/rss-sled-plan.json index 2dbd5f04b0..204dddff99 100644 --- a/schema/rss-sled-plan.json +++ b/schema/rss-sled-plan.json @@ -616,7 +616,7 @@ } }, "Ipv6Subnet": { - "description": "Wraps an [`Ipv6Network`] with a compile-time prefix length.", + "description": "Wraps an [`Ipv6Net`] with a compile-time prefix length.", "type": "object", "required": [ "net" diff --git a/schema/start-sled-agent-request.json b/schema/start-sled-agent-request.json index 9b97be9a00..98dfcea61c 100644 --- a/schema/start-sled-agent-request.json +++ b/schema/start-sled-agent-request.json @@ -40,7 +40,7 @@ } }, "Ipv6Subnet": { - "description": "Wraps an [`Ipv6Network`] with a compile-time prefix length.", + "description": "Wraps an [`Ipv6Net`] with a compile-time prefix length.", "type": "object", "required": [ "net" From c427295e9a8e57eae77cb530a4c779981953abeb Mon Sep 17 00:00:00 2001 From: Adam Leventhal Date: Thu, 23 May 2024 12:18:00 -0700 Subject: [PATCH 22/23] Update common/src/address.rs Co-authored-by: Andrew J. Stone --- common/src/address.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/address.rs b/common/src/address.rs index c0aeb1a70f..b7476d6ff4 100644 --- a/common/src/address.rs +++ b/common/src/address.rs @@ -76,7 +76,7 @@ pub const NTP_PORT: u16 = 123; /// The length for all VPC IPv6 prefixes pub const VPC_IPV6_PREFIX_LENGTH: u8 = 48; -/// The prefix length for all VPC Sunets +/// The prefix length for all VPC subnets pub const VPC_SUBNET_IPV6_PREFIX_LENGTH: u8 = 64; // The number of ports available to an SNAT IP. From 24a455b54b0de9fe8426f3627147309fa5ebf204 Mon Sep 17 00:00:00 2001 From: "Adam H. Leventhal" Date: Thu, 23 May 2024 12:19:18 -0700 Subject: [PATCH 23/23] dead code --- common/src/api/external/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index 9454a20efa..07a7776f1e 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -1249,8 +1249,6 @@ pub trait Ipv6NetExt { impl Ipv6NetExt for oxnet::Ipv6Net { fn is_vpc_prefix(&self) -> bool { - // /// The prefix length for all VPC subnets - // pub const VPC_SUBNET_IPV6_PREFIX_LENGTH: u8 = 64; self.is_unique_local() && self.width() == Self::VPC_IPV6_PREFIX_LENGTH }