Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
68a0df3
[multicast] Drop (m)vlan from multicast groups
zeeshanlakhani Nov 30, 2025
5717f67
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 2, 2025
016f7e1
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 3, 2025
e2a1281
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 3, 2025
82fb9df
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 5, 2025
dac4df1
[api] prep for drop of vlan
zeeshanlakhani Dec 5, 2025
56d9a8b
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 6, 2025
064268f
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 6, 2025
5611baf
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 6, 2025
b5ae188
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 6, 2025
029f9d6
[fmt] ..
zeeshanlakhani Dec 6, 2025
952a4c8
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 9, 2025
a7bdb6c
..
zeeshanlakhani Dec 9, 2025
894d295
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 16, 2025
27bb9e0
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 16, 2025
6322c39
[post-merge] api fixins
zeeshanlakhani Dec 16, 2025
bc20284
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 17, 2025
5ca441d
[post-merge] leftover cleanup during conflicts
zeeshanlakhani Dec 17, 2025
7426d09
Merge remote-tracking branch 'origin/zl/mcast-implicit-lifecycle' int…
zeeshanlakhani Dec 17, 2025
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
25 changes: 0 additions & 25 deletions nexus/db-model/src/multicast_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,28 +178,6 @@ pub struct ExternalMulticastGroup {
pub vni: Vni,
/// Primary multicast IP address (overlay/external).
pub multicast_ip: IpNetwork,
/// Multicast VLAN (MVLAN) for egress multicast traffic to upstream networks.
///
/// When specified, this VLAN ID is passed to switches (via DPD) as part of
/// the `ExternalForwarding` configuration to tag multicast packets leaving
/// the rack. This enables multicast traffic to traverse VLAN-segmented
/// upstream networks (e.g., peering with external multicast sources/receivers
/// on specific VLANs).
///
/// The MVLAN value is sent to switches during group creation/updates and
/// controls VLAN tagging for egress traffic only; it does not affect ingress
/// multicast traffic received by the rack. Switch port selection for egress
/// traffic remains pending (see TODOs in `nexus/src/app/multicast/dataplane.rs`).
///
/// Valid range when specified: 2-4094 (IEEE 802.1Q; Dendrite requires >= 2).
///
/// Database Type: i16 (INT2) - this field uses `i16` (INT2) for storage
/// efficiency, unlike other VLAN columns in the schema which use `SqlU16`
/// (forcing INT4). Direct `i16` is appropriate here since VLANs fit in
/// INT2's range.
///
/// TODO(multicast): Remove mvlan field - being deprecated from multicast groups
pub mvlan: Option<i16>,
/// Associated underlay group for NAT.
/// Initially None in ["Creating"](MulticastGroupState::Creating) state,
/// populated by reconciler when group becomes ["Active"](MulticastGroupState::Active).
Expand Down Expand Up @@ -339,7 +317,6 @@ pub struct IncompleteExternalMulticastGroup {
pub ip_pool_id: Uuid,
/// Optional address requesting a specific multicast IP be allocated.
pub explicit_address: Option<IpNetwork>,
pub mvlan: Option<i16>,
pub vni: Vni,
}

Expand All @@ -351,7 +328,6 @@ pub struct IncompleteExternalMulticastGroupParams {
pub description: String,
pub ip_pool_id: Uuid,
pub explicit_address: Option<IpAddr>,
pub mvlan: Option<i16>,
pub vni: Vni,
}

Expand All @@ -365,7 +341,6 @@ impl IncompleteExternalMulticastGroup {
time_created: Utc::now(),
ip_pool_id: params.ip_pool_id,
explicit_address: params.explicit_address.map(|ip| ip.into()),
mvlan: params.mvlan,
vni: params.vni,
}
}
Expand Down
3 changes: 2 additions & 1 deletion nexus/db-model/src/schema_versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::{collections::BTreeMap, sync::LazyLock};
///
/// This must be updated when you change the database schema. Refer to
/// schema/crdb/README.adoc in the root of this repository for details.
pub const SCHEMA_VERSION: Version = Version::new(214, 0, 0);
pub const SCHEMA_VERSION: Version = Version::new(215, 0, 0);

/// List of all past database schema versions, in *reverse* order
///
Expand All @@ -28,6 +28,7 @@ static KNOWN_VERSIONS: LazyLock<Vec<KnownVersion>> = LazyLock::new(|| {
// | leaving the first copy as an example for the next person.
// v
// KnownVersion::new(next_int, "unique-dirname-with-the-sql-files"),
KnownVersion::new(215, "multicast-drop-mvlan"),
KnownVersion::new(214, "multicast-implicit-lifecycle"),
KnownVersion::new(213, "fm-cases"),
KnownVersion::new(212, "local-storage-disk-type"),
Expand Down
64 changes: 7 additions & 57 deletions nexus/db-queries/src/db/datastore/multicast/groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ use omicron_common::api::external::{
IdentityMetadataCreateParams, ListResultVec, LookupResult, LookupType,
ResourceType, UpdateResult,
};
use omicron_common::vlan::VlanID;
use omicron_uuid_kinds::{GenericUuid, MulticastGroupUuid};

use super::EnsureUnderlayResult;
Expand All @@ -57,41 +56,23 @@ use crate::db::update_and_check::{UpdateAndCheck, UpdateStatus};
/// External multicast group with computed source IPs from members.
///
/// The `source_ips` field contains the union of all member source IPs,
/// computed via a separate query. This struct enables a clean `TryFrom`
/// computed via a separate query. This struct enables a clean `From`
/// conversion to the API view.
///
// TODO(multicast): Remove mvlan field, being deprecated from multicast groups
#[derive(Clone, Debug)]
pub struct ExternalMulticastGroupWithSources {
pub group: ExternalMulticastGroup,
pub source_ips: Vec<IpAddr>,
}

impl TryFrom<ExternalMulticastGroupWithSources> for views::MulticastGroup {
type Error = external::Error;

fn try_from(
value: ExternalMulticastGroupWithSources,
) -> Result<Self, Self::Error> {
let mvlan = value
.group
.mvlan
.map(|vlan| VlanID::new(vlan as u16))
.transpose()
.map_err(|e| {
external::Error::internal_error(&format!(
"invalid VLAN ID: {e:#}"
))
})?;

Ok(views::MulticastGroup {
impl From<ExternalMulticastGroupWithSources> for views::MulticastGroup {
fn from(value: ExternalMulticastGroupWithSources) -> Self {
views::MulticastGroup {
identity: value.group.identity(),
multicast_ip: value.group.multicast_ip.ip(),
source_ips: value.source_ips,
mvlan,
ip_pool_id: value.group.ip_pool_id,
state: value.group.state.to_string(),
})
}
}
}

Expand All @@ -104,7 +85,6 @@ pub(crate) struct MulticastGroupAllocationParams {
pub identity: IdentityMetadataCreateParams,
pub ip: Option<IpAddr>,
pub pool: Option<authz::IpPool>,
pub mvlan: Option<VlanID>,
/// Derived for whether the joining member has source IPs.
/// Used for default pool selection -> if true, prefer SSM pool first.
pub has_sources: bool,
Expand Down Expand Up @@ -253,7 +233,6 @@ impl DataStore {
identity: params.identity.clone(),
ip: params.multicast_ip,
pool: authz_pool,
mvlan: params.mvlan,
has_sources: params.has_sources,
},
)
Expand Down Expand Up @@ -573,7 +552,6 @@ impl DataStore {
description: params.identity.description.clone(),
ip_pool_id: authz_pool.id(),
explicit_address: params.ip,
mvlan: params.mvlan.map(|vlan_id| u16::from(vlan_id) as i16),
vni,
},
);
Expand Down Expand Up @@ -956,7 +934,6 @@ mod tests {
description: "First group".to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: false,
};
datastore
Expand All @@ -971,7 +948,6 @@ mod tests {
description: "Second group".to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: false,
};
datastore
Expand All @@ -986,7 +962,6 @@ mod tests {
description: "Should fail".to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: false,
};
let res3 = datastore
Expand Down Expand Up @@ -1059,7 +1034,6 @@ mod tests {
description: "Group using default pool".to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: false,
};

Expand All @@ -1084,7 +1058,6 @@ mod tests {
description: "Group with explicit pool".to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: false,
};
let group_explicit = datastore
Expand Down Expand Up @@ -1211,7 +1184,6 @@ mod tests {
description: "Comprehensive test group".to_string(),
},
multicast_ip: Some("224.1.3.3".parse().unwrap()),
mvlan: None,
has_sources: false,
};

Expand Down Expand Up @@ -1315,7 +1287,6 @@ mod tests {
description: "Group for parent_id testing".to_string(),
},
multicast_ip: Some("224.3.1.5".parse().unwrap()),
mvlan: None,
has_sources: false,
};

Expand Down Expand Up @@ -1785,7 +1756,6 @@ mod tests {
description: "Group for duplicate testing".to_string(),
},
multicast_ip: Some("224.3.1.5".parse().unwrap()),
mvlan: None,
has_sources: false,
};

Expand Down Expand Up @@ -1918,7 +1888,6 @@ mod tests {
.to_string(),
},
multicast_ip: None, // Let it allocate from pool
mvlan: None,
has_sources: false,
};
let group = datastore
Expand Down Expand Up @@ -2131,7 +2100,6 @@ mod tests {
description: "Group for IP reuse test".to_string(),
},
multicast_ip: Some(target_ip),
mvlan: None,
has_sources: false,
};

Expand All @@ -2158,7 +2126,6 @@ mod tests {
description: "Second group reusing same IP".to_string(),
},
multicast_ip: Some(target_ip),
mvlan: None,
has_sources: false,
};

Expand Down Expand Up @@ -2243,7 +2210,6 @@ mod tests {
description: "First group to exhaust pool".to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: false,
};

Expand All @@ -2260,7 +2226,6 @@ mod tests {
description: "Second group should fail".to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: false,
};

Expand Down Expand Up @@ -2290,7 +2255,6 @@ mod tests {
.to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: false,
};

Expand Down Expand Up @@ -2376,7 +2340,6 @@ mod tests {
description: "Group for deallocation testing".to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: false,
};

Expand Down Expand Up @@ -2500,8 +2463,7 @@ mod tests {
description: "Test group for fetch operations".to_string(),
},
multicast_ip: Some("224.100.10.5".parse().unwrap()),
mvlan: None,
has_sources: false,
has_sources: true,
};

let group = datastore
Expand Down Expand Up @@ -2606,7 +2568,6 @@ mod tests {
description: "Fleet-wide group 1".to_string(),
},
multicast_ip: Some("224.100.20.10".parse().unwrap()),
mvlan: None,
has_sources: false,
};

Expand All @@ -2616,7 +2577,6 @@ mod tests {
description: "Fleet-wide group 2".to_string(),
},
multicast_ip: Some("224.100.20.11".parse().unwrap()),
mvlan: None,
has_sources: false,
};

Expand All @@ -2626,7 +2586,6 @@ mod tests {
description: "Fleet-wide group 3".to_string(),
},
multicast_ip: Some("224.100.20.12".parse().unwrap()),
mvlan: None,
has_sources: false,
};

Expand Down Expand Up @@ -2734,7 +2693,6 @@ mod tests {
description: "Test group for state transitions".to_string(),
},
multicast_ip: Some("224.100.30.5".parse().unwrap()),
mvlan: None,
has_sources: false,
};

Expand Down Expand Up @@ -3073,8 +3031,7 @@ mod tests {
description: "Group using ASM pool".to_string(),
},
multicast_ip: None, // No explicit IP - triggers pool auto-selection
mvlan: None,
has_sources: false,
has_sources: true, // Has sources
};

// This should succeed via ASM pool (no SSM pool exists)
Expand Down Expand Up @@ -3163,7 +3120,6 @@ mod tests {
description: "Should fall back to ASM when no SSM".to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: true,
};
let fallback_group = datastore
Expand Down Expand Up @@ -3235,7 +3191,6 @@ mod tests {
description: "Should prefer SSM over ASM".to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: true,
};
let ssm_group = datastore
Expand All @@ -3258,7 +3213,6 @@ mod tests {
description: "has_sources=false should use ASM".to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: false,
};
let asm_group = datastore
Expand Down Expand Up @@ -3392,7 +3346,6 @@ mod tests {
.to_string(),
},
multicast_ip: None,
mvlan: None,
has_sources: true,
};
let group = datastore
Expand Down Expand Up @@ -3472,7 +3425,6 @@ mod tests {
description: "First group for collision test".to_string(),
},
multicast_ip: Some("224.10.1.1".parse().unwrap()),
mvlan: None,
has_sources: false,
};
let external_group1 = datastore
Expand All @@ -3487,7 +3439,6 @@ mod tests {
description: "Second group for collision test".to_string(),
},
multicast_ip: Some("224.10.1.2".parse().unwrap()),
mvlan: None,
has_sources: false,
};
let external_group2 = datastore
Expand Down Expand Up @@ -3610,7 +3561,6 @@ mod tests {
description: "Group for salt testing".to_string(),
},
multicast_ip: Some("224.20.1.1".parse().unwrap()),
mvlan: None,
has_sources: false,
};
let external_group = datastore
Expand Down
1 change: 0 additions & 1 deletion nexus/db-queries/src/db/datastore/multicast/members.rs
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,6 @@ mod tests {
},
multicast_ip: Some("224.10.1.6".parse().unwrap()),
// Pool resolved via authz_pool argument to datastore call
mvlan: None,
has_sources: false,
};

Expand Down
1 change: 0 additions & 1 deletion nexus/db-queries/src/db/pub_test_utils/multicast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ pub async fn create_test_group_with_state(
description: format!("Test group: {group_name}"),
},
multicast_ip: Some(multicast_ip.parse().unwrap()),
mvlan: None,
has_sources: false,
};

Expand Down
Loading
Loading