Skip to content

Commit 98bf71e

Browse files
[feat] Add IP pool multicast support
This work introduces multicast IP pool capabilities to support external multicast traffic routing through the rack's switching infrastructure. Includes: - Add IpPoolType enum (unicast/multicast) with unicast as default - Add multicast pool fields: switch_port_uplinks (UUID[]), mvlan (VLAN ID) - Add database migration (multicast-support/up01.sql) with new columns and indexes - Add ASM/SSM range validation for multicast pools to prevent mixing - Add pool type-aware resolution for IP allocation - Add custom deserializer for switch port uplinks with deduplication - Update external API params/views for multicast pool configuration - Add SSM constants (IPV4_SSM_SUBNET, IPV6_SSM_FLAG_FIELD) for validation Database schema updates: - ip_pool table: pool_type, switch_port_uplinks, mvlan columns - Index on pool_type for efficient filtering - Migration preserves existing pools as unicast type by default This provides the foundation for multicast group functionality while maintaining full backward compatibility with existing unicast pools. References (for review): - RFD 488: https://rfd.shared.oxide.computer/rfd/488 - Dendrite PRs (based on recency): * oxidecomputer/dendrite#132 * oxidecomputer/dendrite#109 * oxidecomputer/dendrite#14
1 parent 65c8aed commit 98bf71e

File tree

34 files changed

+2295
-173
lines changed

34 files changed

+2295
-173
lines changed

Cargo.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ digest = "0.10.7"
436436
dns-server = { path = "dns-server" }
437437
dns-server-api = { path = "dns-server-api" }
438438
dns-service-client = { path = "clients/dns-service-client" }
439-
dpd-client = { git = "https://github.com/oxidecomputer/dendrite", rev = "738c80d18d5e94eda367440ade7743e9d9f124de" }
439+
dpd-client = { git = "https://github.com/oxidecomputer/dendrite", rev = "6ba23e71121c196e1e3c4e0621ba7a6f046237c7" }
440440
dropshot = { version = "0.16.3", features = [ "usdt-probes" ] }
441441
dyn-clone = "1.0.20"
442442
either = "1.15.0"

common/src/address.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ pub const AZ_PREFIX: u8 = 48;
2222
pub const RACK_PREFIX: u8 = 56;
2323
pub const SLED_PREFIX: u8 = 64;
2424

25+
// Multicast constants
26+
27+
/// IPv4 Source-Specific Multicast (SSM) subnet as defined in RFC 4607:
28+
/// <https://tools.ietf.org/html/rfc4607>.
29+
pub const IPV4_SSM_SUBNET: oxnet::Ipv4Net =
30+
oxnet::Ipv4Net::new_unchecked(Ipv4Addr::new(232, 0, 0, 0), 8);
31+
32+
/// IPv6 Source-Specific Multicast (SSM) flag field value as defined in RFC 4607:
33+
/// <https://tools.ietf.org/html/rfc4607>.
34+
/// This is the flags nibble (high nibble of second byte) for FF3x::/32 addresses.
35+
pub const IPV6_SSM_FLAG_FIELD: u8 = 3;
36+
2537
/// maximum possible value for a tcp or udp port
2638
pub const MAX_PORT: u16 = u16::MAX;
2739

common/src/vlan.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
//! VLAN ID wrapper.
66
77
use crate::api::external::Error;
8+
use schemars::JsonSchema;
89
use serde::Deserialize;
10+
use serde::Serialize;
911
use std::fmt;
1012
use std::str::FromStr;
1113

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

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

1922
impl VlanID {
@@ -44,3 +47,20 @@ impl FromStr for VlanID {
4447
)
4548
}
4649
}
50+
51+
impl From<VlanID> for u16 {
52+
fn from(vlan_id: VlanID) -> u16 {
53+
vlan_id.0
54+
}
55+
}
56+
57+
impl slog::Value for VlanID {
58+
fn serialize(
59+
&self,
60+
_record: &slog::Record,
61+
key: slog::Key,
62+
serializer: &mut dyn slog::Serializer,
63+
) -> slog::Result {
64+
serializer.emit_u16(key, self.0)
65+
}
66+
}

end-to-end-tests/src/bin/bootstrap.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use end_to_end_tests::helpers::{
66
use omicron_test_utils::dev::poll::{CondCheckError, wait_for_condition};
77
use oxide_client::types::{
88
ByteCount, DeviceAccessTokenRequest, DeviceAuthRequest, DeviceAuthVerify,
9-
DiskCreate, DiskSource, IpPoolCreate, IpPoolLinkSilo, IpVersion, NameOrId,
10-
SiloQuotasUpdate,
9+
DiskCreate, DiskSource, IpPoolCreate, IpPoolLinkSilo, IpPoolType,
10+
IpVersion, NameOrId, SiloQuotasUpdate,
1111
};
1212
use oxide_client::{
1313
ClientConsoleAuthExt, ClientDisksExt, ClientProjectsExt,
@@ -53,6 +53,9 @@ async fn run_test() -> Result<()> {
5353
name: pool_name.parse().unwrap(),
5454
description: "Default IP pool".to_string(),
5555
ip_version,
56+
mvlan: None,
57+
pool_type: IpPoolType::Unicast,
58+
switch_port_uplinks: None,
5659
})
5760
.send()
5861
.await?;

end-to-end-tests/src/bin/commtest.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use oxide_client::{
77
ClientSystemHardwareExt, ClientSystemIpPoolsExt, ClientSystemStatusExt,
88
ClientVpcsExt,
99
types::{
10-
IpPoolCreate, IpPoolLinkSilo, IpRange, IpVersion, Name, NameOrId,
11-
PingStatus, ProbeCreate, ProbeInfo, ProjectCreate,
10+
IpPoolCreate, IpPoolLinkSilo, IpPoolType, IpRange, IpVersion, Name,
11+
NameOrId, PingStatus, ProbeCreate, ProbeInfo, ProjectCreate,
1212
UsernamePasswordCredentials,
1313
},
1414
};
@@ -295,6 +295,9 @@ async fn rack_prepare(
295295
name: pool_name.parse().unwrap(),
296296
description: "Default IP pool".to_string(),
297297
ip_version,
298+
mvlan: None,
299+
pool_type: IpPoolType::Unicast,
300+
switch_port_uplinks: None,
298301
})
299302
.send()
300303
.await?;

nexus/db-model/src/generation.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use diesel::pg::Pg;
88
use diesel::serialize::{self, ToSql};
99
use diesel::sql_types;
1010
use omicron_common::api::external;
11+
use schemars::JsonSchema;
1112
use serde::{Deserialize, Serialize};
1213
use std::convert::TryFrom;
1314

@@ -23,6 +24,7 @@ use std::convert::TryFrom;
2324
FromSqlRow,
2425
Serialize,
2526
Deserialize,
27+
JsonSchema,
2628
)]
2729
#[diesel(sql_type = sql_types::BigInt)]
2830
#[repr(transparent)]

0 commit comments

Comments
 (0)