Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalize network_interface table to allow for new kinds of NICs. #2767

Merged
merged 7 commits into from
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
9 changes: 5 additions & 4 deletions common/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ pub enum ResourceType {
Image,
Instance,
IpPool,
NetworkInterface,
InstanceNetworkInterface,
PhysicalDisk,
Rack,
Service,
Expand Down Expand Up @@ -2044,9 +2044,10 @@ impl TryFrom<i32> for Vni {
}
}

/// A `NetworkInterface` represents a virtual network interface device.
/// An `InstanceNetworkInterface` represents a virtual network interface device
/// attached to an instance.
#[derive(ObjectIdentity, Clone, Debug, Deserialize, JsonSchema, Serialize)]
pub struct NetworkInterface {
pub struct InstanceNetworkInterface {
/// common identifying metadata
#[serde(flatten)]
pub identity: IdentityMetadata,
Expand All @@ -2064,9 +2065,9 @@ pub struct NetworkInterface {
pub mac: MacAddr,

/// The IP address assigned to this interface.
pub ip: IpAddr,
// TODO-correctness: We need to split this into an optional V4 and optional
// V6 address, at least one of which must be specified.
pub ip: IpAddr,
/// True if this interface is the primary for the instance to which it's
/// attached.
pub primary: bool,
Expand Down
85 changes: 71 additions & 14 deletions common/src/sql/dbinit.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,15 @@ CREATE UNIQUE INDEX ON omicron.public.vpc_subnet (
) WHERE
time_deleted IS NULL;

/* The kind of network interface. */
CREATE TYPE omicron.public.network_interface_kind AS ENUM (
/* An interface attached to a guest instance. */
'instance',

/* An interface attached to a service. */
'service'
);

CREATE TABLE omicron.public.network_interface (
/* Identity metadata (resource) */
id UUID PRIMARY KEY,
Expand All @@ -1046,11 +1055,14 @@ CREATE TABLE omicron.public.network_interface (
/* Indicates that the object has been deleted */
time_deleted TIMESTAMPTZ,

/* FK into Instance table.
* Note that interfaces are always attached to a particular instance.
* IP addresses may be reserved, but this is a different resource.
/* The kind of network interface, e.g., instance */
kind omicron.public.network_interface_kind NOT NULL,

/*
* FK into the parent resource of this interface (e.g. Instance, Service)
* as determined by the `kind`.
*/
instance_id UUID NOT NULL,
parent_id UUID NOT NULL,

/* FK into VPC table */
vpc_id UUID NOT NULL,
Expand All @@ -1065,21 +1077,65 @@ CREATE TABLE omicron.public.network_interface (
*/
mac INT8 NOT NULL,

/* The private VPC IP address of the interface. */
ip INET NOT NULL,

/*
* Limited to 8 NICs per instance. This value must be kept in sync with
* `crate::nexus::MAX_NICS_PER_INSTANCE`.
*/
slot INT2 NOT NULL CHECK (slot >= 0 AND slot < 8),

/* True if this interface is the primary interface for the instance.
/* True if this interface is the primary interface.
*
* The primary interface appears in DNS and its address is used for external
* connectivity for the instance.
* connectivity.
*/
is_primary BOOL NOT NULL
);

/* A view of the network_interface table for just instance-kind records. */
CREATE VIEW omicron.public.instance_network_interface AS
SELECT
id,
name,
description,
time_created,
time_modified,
time_deleted,
parent_id AS instance_id,
vpc_id,
subnet_id,
mac,
ip,
slot,
is_primary
FROM
omicron.public.network_interface
WHERE
kind = 'instance';

/* A view of the network_interface table for just service-kind records. */
CREATE VIEW omicron.public.service_network_interface AS
SELECT
id,
name,
description,
time_created,
time_modified,
time_deleted,
parent_id AS service_id,
vpc_id,
subnet_id,
mac,
ip,
slot,
is_primary
FROM
omicron.public.network_interface
WHERE
kind = 'service';

/* TODO-completeness

* We currently have a NetworkInterface table with the IP and MAC addresses inline.
Expand All @@ -1105,17 +1161,18 @@ CREATE UNIQUE INDEX ON omicron.public.network_interface (
time_deleted IS NULL;

/*
* Index used to verify that an Instance's networking is contained
* within a single VPC, and that all interfaces are in unique VPC
* Subnets.
* Index used to verify that all interfaces for a resource (e.g. Instance,
* Service) are contained within a single VPC, and that all interfaces are
* in unique VPC Subnets.
*
* This is also used to quickly find the primary interface for an
* instance, since we store the `is_primary` column. Such queries are
* mostly used when setting a new primary interface for an instance.
* This is also used to quickly find the primary interface since
* we store the `is_primary` column. Such queries are mostly used
* when setting a new primary interface.
*/
CREATE UNIQUE INDEX ON omicron.public.network_interface (
instance_id,
name
parent_id,
name,
kind
)
STORING (vpc_id, subnet_id, is_primary)
WHERE
Expand Down
9 changes: 9 additions & 0 deletions nexus/db-model/src/macaddr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ impl MacAddr {
// for an initial discussion of the customer/system address range split.
pub const MIN_GUEST_ADDR: i64 = 0xA8_40_25_F0_00_00;
pub const MAX_GUEST_ADDR: i64 = 0xA8_40_25_FE_FF_FF;
pub const MIN_SYSTEM_ADDR: i64 = 0xA8_40_25_FF_00_00;
pub const MAX_SYSTEM_ADDR: i64 = 0xA8_40_25_FF_FF_FF;

/// Generate a random MAC address for a guest network interface
pub fn random_guest() -> Self {
Expand All @@ -34,6 +36,13 @@ impl MacAddr {
Self::from_i64(value)
}

/// Generate a random MAC address in the system address range
pub fn random_system() -> Self {
let value = thread_rng()
.gen_range(Self::MIN_SYSTEM_ADDR..=Self::MAX_SYSTEM_ADDR);
Self::from_i64(value)
}

/// Construct a MAC address from its i64 big-endian byte representation.
// NOTE: This is the representation used in the database.
pub(crate) fn from_i64(value: i64) -> Self {
Expand Down
Loading