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
30 changes: 30 additions & 0 deletions common/src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,36 @@ pub const AZ_PREFIX: u8 = 48;
pub const RACK_PREFIX: u8 = 56;
pub const SLED_PREFIX: u8 = 64;

// Multicast constants

/// IPv4 Source-Specific Multicast (SSM) subnet as defined in RFC 4607:
/// <https://tools.ietf.org/html/rfc4607>.
///
/// RFC 4607 Section 3 allocates 232.0.0.0/8 as the IPv4 SSM address range.
/// This is a single contiguous block, unlike IPv6 which has per-scope ranges.
pub const IPV4_SSM_SUBNET: oxnet::Ipv4Net =
oxnet::Ipv4Net::new_unchecked(Ipv4Addr::new(232, 0, 0, 0), 8);

/// IPv6 Source-Specific Multicast (SSM) subnet as defined in RFC 4607:
/// <https://tools.ietf.org/html/rfc4607>.
///
/// RFC 4607 Section 3 specifies "FF3x::/32 for each scope x" - meaning one
/// /32 block per scope (FF30::/32, FF31::/32, ..., FF3F::/32).
///
/// We use /12 as an implementation convenience to match all these blocks with
/// a single subnet. This works because all SSM addresses share the same first
/// 12 bits:
/// - Bits 0-7: 11111111 (0xFF, multicast prefix)
/// - Bits 8-11: 0011 (flag field = 3, indicating SSM)
/// - Bits 12-15: xxxx (scope field, any value 0-F)
///
/// Thus FF30::/12 efficiently matches FF30:: through FF3F:FFFF:...:FFFF,
/// covering all SSM scopes.
pub const IPV6_SSM_SUBNET: oxnet::Ipv6Net = oxnet::Ipv6Net::new_unchecked(
Ipv6Addr::new(0xff30, 0, 0, 0, 0, 0, 0, 0),
12,
);

/// maximum possible value for a tcp or udp port
pub const MAX_PORT: u16 = u16::MAX;

Expand Down
22 changes: 21 additions & 1 deletion common/src/vlan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@
//! VLAN ID wrapper.

use crate::api::external::Error;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use std::fmt;
use std::str::FromStr;

/// The maximum VLAN value (inclusive), as specified by IEEE 802.1Q.
pub const VLAN_MAX: u16 = 4094;

/// Wrapper around a VLAN ID, ensuring it is valid.
#[derive(Debug, Deserialize, Clone, Copy)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy, JsonSchema)]
#[serde(rename = "VlanId")]
pub struct VlanID(u16);

impl VlanID {
Expand Down Expand Up @@ -44,3 +47,20 @@ impl FromStr for VlanID {
)
}
}

impl From<VlanID> for u16 {
fn from(vlan_id: VlanID) -> u16 {
vlan_id.0
}
}

impl slog::Value for VlanID {
fn serialize(
&self,
_record: &slog::Record,
key: slog::Key,
serializer: &mut dyn slog::Serializer,
) -> slog::Result {
serializer.emit_u16(key, self.0)
}
}
2 changes: 2 additions & 0 deletions docs/control-plane-architecture.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ NOTE: Much of this material originally came from <<rfd48>> and <<rfd61>>. This

NOTE: The RFD references in this documentation may be Oxide-internal. Where possible, we're trying to move relevant documentation from those RFDs into docs here.

See also: link:../notes/multicast-architecture.adoc[Multicast Architecture: VLAN Scope]

== What is the control plane

In software systems the terms **data plane** and **control plane** are often used to refer to the parts of the system that directly provide resources to users (the data plane) and the parts that support the configuration, control, monitoring, and operation of the system (the control plane). Within the Oxide system, we say that the data plane comprises those parts that provide CPU resources (including both the host CPU and hypervisor software), storage resources, and network resources. The control plane provides the APIs through which users provision, configure, and monitor these resources and the mechanisms through which these APIs are implemented. Also part of the control plane are the APIs and facilities through which operators manage the system itself, including fault management, alerting, software updates for various components of the system, and so on.
Expand Down
2 changes: 2 additions & 0 deletions docs/networking.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

This is a very rough introduction to how networking works within the Oxide system and particularly the control plane (Omicron). Much more information is available in various RFDs, particularly <<rfd63>>.

See also: link:../notes/multicast-architecture.adoc[Multicast Architecture: VLAN Scope]

== IPv6: the least you need to know

While IPv4 can be used for connectivity between Omicron and the outside world, everything else in the system uses IPv6. This section provides a _very_ cursory introduction to IPv6 for people only familiar with IPv4. You can skip this if you know IPv6. If you want slightly more detail than what's here, see https://www.roesen.org/files/ipv6_cheat_sheet.pdf[this cheat sheet].
Expand Down
5 changes: 3 additions & 2 deletions end-to-end-tests/src/bin/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use end_to_end_tests::helpers::{
use omicron_test_utils::dev::poll::{CondCheckError, wait_for_condition};
use oxide_client::types::{
ByteCount, DeviceAccessTokenRequest, DeviceAuthRequest, DeviceAuthVerify,
DiskCreate, DiskSource, IpPoolCreate, IpPoolLinkSilo, IpVersion, NameOrId,
SiloQuotasUpdate,
DiskCreate, DiskSource, IpPoolCreate, IpPoolLinkSilo, IpPoolType,
IpVersion, NameOrId, SiloQuotasUpdate,
};
use oxide_client::{
ClientConsoleAuthExt, ClientDisksExt, ClientProjectsExt,
Expand Down Expand Up @@ -53,6 +53,7 @@ async fn run_test() -> Result<()> {
name: pool_name.parse().unwrap(),
description: "Default IP pool".to_string(),
ip_version,
pool_type: IpPoolType::Unicast,
})
.send()
.await?;
Expand Down
5 changes: 3 additions & 2 deletions end-to-end-tests/src/bin/commtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use oxide_client::{
ClientSystemHardwareExt, ClientSystemIpPoolsExt, ClientSystemStatusExt,
ClientVpcsExt,
types::{
IpPoolCreate, IpPoolLinkSilo, IpRange, IpVersion, Name, NameOrId,
PingStatus, ProbeCreate, ProbeInfo, ProjectCreate,
IpPoolCreate, IpPoolLinkSilo, IpPoolType, IpRange, IpVersion, Name,
NameOrId, PingStatus, ProbeCreate, ProbeInfo, ProjectCreate,
UsernamePasswordCredentials,
},
};
Expand Down Expand Up @@ -295,6 +295,7 @@ async fn rack_prepare(
name: pool_name.parse().unwrap(),
description: "Default IP pool".to_string(),
ip_version,
pool_type: IpPoolType::Unicast,
})
.send()
.await?;
Expand Down
2 changes: 2 additions & 0 deletions nexus/db-model/src/generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use diesel::pg::Pg;
use diesel::serialize::{self, ToSql};
use diesel::sql_types;
use omicron_common::api::external;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;

Expand All @@ -23,6 +24,7 @@ use std::convert::TryFrom;
FromSqlRow,
Serialize,
Deserialize,
JsonSchema,
)]
#[diesel(sql_type = sql_types::BigInt)]
#[repr(transparent)]
Expand Down
Loading
Loading