Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 23 additions & 10 deletions dev-tools/omdb/src/bin/omdb/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ use indicatif::ProgressBar;
use indicatif::ProgressDrawTarget;
use indicatif::ProgressStyle;
use internal_dns_types::names::ServiceName;
use ipnetwork::IpNetwork;
use nexus_config::PostgresConfigWithUrl;
use nexus_config::RegionAllocationStrategy;
use nexus_db_errors::OptionalError;
Expand Down Expand Up @@ -168,6 +167,8 @@ use std::collections::HashMap;
use std::collections::HashSet;
use std::fmt::Display;
use std::future::Future;
use std::net::Ipv4Addr;
use std::net::Ipv6Addr;
use std::num::NonZeroU32;
use std::str::FromStr;
use std::sync::Arc;
Expand Down Expand Up @@ -5376,12 +5377,16 @@ async fn cmd_db_network_list_vnics(
#[derive(Tabled)]
#[tabled(rename_all = "SCREAMING_SNAKE_CASE")]
struct NicRow {
ip: IpNetwork,
#[tabled(display_with = "option_impl_display")]
ipv4: Option<Ipv4Addr>,
#[tabled(display_with = "option_impl_display")]
ipv6: Option<Ipv6Addr>,
mac: MacAddr,
slot: u8,
primary: bool,
kind: &'static str,
subnet: String,
ipv4_subnet: String,
ipv6_subnet: String,
parent_id: Uuid,
parent_name: String,
}
Expand Down Expand Up @@ -5471,7 +5476,7 @@ async fn cmd_db_network_list_vnics(
}
};

let subnet = {
let (ipv4_subnet, ipv6_subnet) = {
use nexus_db_schema::schema::vpc_subnet::dsl;
let subnet = match dsl::vpc_subnet
.filter(dsl::id.eq(nic.subnet_id))
Expand All @@ -5488,28 +5493,36 @@ async fn cmd_db_network_list_vnics(
continue;
}
};

if nic.ip.is_ipv4() {
let ipv4_subnet = if nic.ipv4.is_some() {
subnet.ipv4_block.to_string()
} else {
String::from("-")
};
let ipv6_subnet = if nic.ipv6.is_some() {
subnet.ipv6_block.to_string()
}
} else {
String::from("-")
};
(ipv4_subnet, ipv6_subnet)
};

let row = NicRow {
ip: nic.ip,
ipv4: nic.ipv4.map(Into::into),
ipv6: nic.ipv6.map(Into::into),
mac: *nic.mac,
slot: *nic.slot,
primary: nic.primary,
kind,
subnet,
ipv4_subnet,
ipv6_subnet,
parent_id: nic.parent_id,
parent_name,
};
rows.push(row);
}

rows.sort_by(|a, b| a.ip.cmp(&b.ip));
// Sort by IPv4 address, and then IPv6 address.
rows.sort_by(|a, b| a.ipv4.cmp(&b.ipv4).then_with(|| a.ipv6.cmp(&b.ipv6)));
let table = tabled::Table::new(rows)
.with(tabled::settings::Style::empty())
.to_string();
Expand Down
92 changes: 92 additions & 0 deletions nexus/db-model/src/ipv4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! Database-friendly IPv4 addresses

use diesel::backend::Backend;
use diesel::deserialize;
use diesel::deserialize::FromSql;
use diesel::pg::Pg;
use diesel::serialize;
use diesel::serialize::Output;
use diesel::serialize::ToSql;
use diesel::sql_types::Inet;
use ipnetwork::IpNetwork;
use ipnetwork::Ipv4Network;
use omicron_common::api::external::Error;
use serde::Deserialize;
use serde::Serialize;

#[derive(
Clone,
Copy,
AsExpression,
FromSqlRow,
PartialEq,
Ord,
PartialOrd,
Eq,
Deserialize,
Serialize,
)]
#[diesel(sql_type = Inet)]
pub struct Ipv4Addr(std::net::Ipv4Addr);

NewtypeDebug! { () pub struct Ipv4Addr(std::net::Ipv4Addr); }
NewtypeFrom! { () pub struct Ipv4Addr(std::net::Ipv4Addr); }
NewtypeDeref! { () pub struct Ipv4Addr(std::net::Ipv4Addr); }

impl From<&std::net::Ipv4Addr> for Ipv4Addr {
fn from(addr: &std::net::Ipv4Addr) -> Self {
Self(*addr)
}
}

impl From<Ipv4Addr> for std::net::IpAddr {
fn from(value: Ipv4Addr) -> Self {
std::net::IpAddr::from(value.0)
}
}

impl From<&Ipv4Addr> for std::net::IpAddr {
fn from(value: &Ipv4Addr) -> Self {
(*value).into()
}
}

impl From<Ipv4Addr> for Ipv4Network {
fn from(value: Ipv4Addr) -> Self {
Ipv4Network::from(value.0)
}
}

impl From<Ipv4Addr> for IpNetwork {
fn from(value: Ipv4Addr) -> Self {
IpNetwork::V4(Ipv4Network::from(value.0))
}
}

impl ToSql<Inet, Pg> for Ipv4Addr {
fn to_sql<'a>(&'a self, out: &mut Output<'a, '_, Pg>) -> serialize::Result {
let net = IpNetwork::V4(Ipv4Network::from(self.0));
<IpNetwork as ToSql<Inet, Pg>>::to_sql(&net, &mut out.reborrow())
}
}

impl<DB> FromSql<Inet, DB> for Ipv4Addr
where
DB: Backend,
IpNetwork: FromSql<Inet, DB>,
{
fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
match IpNetwork::from_sql(bytes)?.ip() {
std::net::IpAddr::V4(ip) => Ok(Self(ip)),
v6 => {
Err(Box::new(Error::internal_error(
format!("Expected an IPv4 address from the database, found IPv6: '{}'", v6).as_str()
)))
}
}
}
}
24 changes: 24 additions & 0 deletions nexus/db-model/src/ipv6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,30 @@ impl From<&std::net::Ipv6Addr> for Ipv6Addr {
}
}

impl From<Ipv6Addr> for std::net::IpAddr {
fn from(value: Ipv6Addr) -> Self {
value.0.into()
}
}

impl From<&Ipv6Addr> for std::net::IpAddr {
fn from(value: &Ipv6Addr) -> Self {
(*value).into()
}
}

impl From<Ipv6Addr> for Ipv6Network {
fn from(value: Ipv6Addr) -> Self {
Ipv6Network::from(value.0)
}
}

impl From<Ipv6Addr> for IpNetwork {
fn from(value: Ipv6Addr) -> Self {
IpNetwork::V6(Ipv6Network::from(value.0))
}
}

impl ToSql<Inet, Pg> for Ipv6Addr {
fn to_sql<'a>(&'a self, out: &mut Output<'a, '_, Pg>) -> serialize::Result {
let net = IpNetwork::V6(Ipv6Network::from(self.0));
Expand Down
2 changes: 2 additions & 0 deletions nexus/db-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ mod internet_gateway;
mod inventory;
mod ip_pool;
mod ipnet;
pub mod ipv4;
mod ipv4net;
pub mod ipv6;
mod ipv6net;
Expand Down Expand Up @@ -192,6 +193,7 @@ pub use internet_gateway::*;
pub use inventory::*;
pub use ip_pool::*;
pub use ipnet::*;
pub use ipv4::*;
pub use ipv4net::*;
pub use ipv6::*;
pub use ipv6net::*;
Expand Down
Loading
Loading