Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1c9d172
[multicast] implicit group lifecycle with IP pool integration
zeeshanlakhani Nov 29, 2025
f7b87b4
[follow-up] link gateway should be unicast default pool only
zeeshanlakhani Dec 1, 2025
1e3b137
Merge remote-tracking branch 'origin/main' into zl/mcast-implicit-lif…
zeeshanlakhani Dec 2, 2025
4b62ccb
Merge remote-tracking branch 'origin/main' into zl/mcast-implicit-lif…
zeeshanlakhani Dec 3, 2025
655e602
[update] auto-select appropriate SSM/ASM pool when allocating multica…
zeeshanlakhani Dec 3, 2025
7def773
[fix] auth ordering
zeeshanlakhani Dec 5, 2025
f28aa9c
Merge remote-tracking branch 'origin/main' into zl/mcast-implicit-lif…
zeeshanlakhani Dec 5, 2025
bad9f11
[api] version multicast endpoints for implicit group lifecycle
zeeshanlakhani Dec 5, 2025
7b673a5
Merge remote-tracking branch 'origin/main' into zl/mcast-implicit-lif…
zeeshanlakhani Dec 6, 2025
c8242bc
[merge] external api clarity and udpates
zeeshanlakhani Dec 6, 2025
bc472b3
[fmt] ..
zeeshanlakhani Dec 6, 2025
b12e8c1
[fix] minor updates and delegation for API
zeeshanlakhani Dec 6, 2025
709c568
[multicast] Relax multicast address restrictions for flexibility
zeeshanlakhani Dec 9, 2025
39a016a
[dep] oxnet update
zeeshanlakhani Dec 9, 2025
07a36a1
[nit] expose vni
zeeshanlakhani Dec 9, 2025
d940ab3
[review] source IPs per member + xor with salt underlay mapping
zeeshanlakhani Dec 16, 2025
3d4230c
Merge remote-tracking branch 'origin/main' into zl/mcast-implicit-lif…
zeeshanlakhani Dec 16, 2025
dc791eb
[hakari] ..
zeeshanlakhani Dec 16, 2025
57fc06e
[fix] endpoint
zeeshanlakhani Dec 16, 2025
0e0737e
Merge remote-tracking branch 'origin/main' into zl/mcast-implicit-lif…
zeeshanlakhani Dec 17, 2025
52a3d65
Merge remote-tracking branch 'origin/main' into zl/mcast-implicit-lif…
zeeshanlakhani Dec 17, 2025
9794876
[multicast] put_upsert test helper, pool selection tests, and ASM sou…
zeeshanlakhani Dec 17, 2025
68a141c
[minor] missing wait
zeeshanlakhani Dec 17, 2025
f7f3c39
[minor] test fixup
zeeshanlakhani Dec 17, 2025
16b8f12
[perf-cleanup] remove redundant tests and update mcast polling
zeeshanlakhani Dec 19, 2025
4853607
Merge remote-tracking branch 'origin/main' into zl/mcast-test-perf
zeeshanlakhani Jan 11, 2026
e97f1b6
[multicast] further test consolidation and test doc fixes
zeeshanlakhani Jan 12, 2026
837a4d5
[openapi] minor update
zeeshanlakhani Jan 12, 2026
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
532 changes: 115 additions & 417 deletions nexus/db-queries/src/db/datastore/multicast/groups.rs

Large diffs are not rendered by default.

549 changes: 137 additions & 412 deletions nexus/db-queries/src/db/datastore/multicast/members.rs

Large diffs are not rendered by default.

381 changes: 165 additions & 216 deletions nexus/tests/integration_tests/multicast/api.rs

Large diffs are not rendered by default.

1,234 changes: 462 additions & 772 deletions nexus/tests/integration_tests/multicast/authorization.rs

Large diffs are not rendered by default.

419 changes: 86 additions & 333 deletions nexus/tests/integration_tests/multicast/failures.rs

Large diffs are not rendered by default.

483 changes: 162 additions & 321 deletions nexus/tests/integration_tests/multicast/groups.rs

Large diffs are not rendered by default.

988 changes: 169 additions & 819 deletions nexus/tests/integration_tests/multicast/instances.rs

Large diffs are not rendered by default.

92 changes: 60 additions & 32 deletions nexus/tests/integration_tests/multicast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,66 @@ pub(crate) async fn wait_for_instance_sled_assignment(
}
}

/// Wait for an instance to reach Running state, driving simulation on each poll.
///
/// More robust than passively waiting, as it actively drives instance
/// simulation while polling for the Running state.
///
/// Only use for Running transitions. For Stopped state, use `instance_simulate`
/// once followed by `instance_wait_for_state`, as the VMM gets removed during
/// stop and repeated simulation will fail.
pub(crate) async fn instance_wait_for_running_with_simulation(
cptestctx: &ControlPlaneTestContext,
instance_id: InstanceUuid,
) -> Instance {
let expected_state = InstanceState::Running;
let client = &cptestctx.external_client;
let nexus = &cptestctx.server.server_context().nexus;
let url = format!("/v1/instances/{instance_id}");

match wait_for_condition(
|| async {
instance_helpers::instance_simulate(nexus, &instance_id).await;

let response = NexusRequest::object_get(client, &url)
.authn_as(AuthnMode::PrivilegedUser)
.execute()
.await
.map_err(|e| {
CondCheckError::<String>::Failed(format!(
"request failed: {e}"
))
})?;

let instance: Instance = response.parsed_body().map_err(|e| {
CondCheckError::<String>::Failed(format!("parse failed: {e}"))
})?;

if instance.runtime.run_state == expected_state {
Ok(instance)
} else {
Err(CondCheckError::<String>::NotYet)
}
},
&POLL_INTERVAL,
&MULTICAST_OPERATION_TIMEOUT,
)
.await
{
Ok(instance) => instance,
Err(poll::Error::TimedOut(elapsed)) => {
panic!(
"instance {instance_id} did not reach {expected_state:?} within {elapsed:?}"
);
}
Err(poll::Error::PermanentError(err)) => {
panic!(
"failed waiting for instance {instance_id} to reach {expected_state:?}: {err}"
);
}
}
}

/// Verify that inventory-based sled-to-switch-port mapping is correct.
///
/// This validates the entire flow:
Expand Down Expand Up @@ -943,38 +1003,6 @@ pub(crate) async fn wait_for_group_deleted(
}
}

/// Verify a group is either deleted or in one of the expected states.
///
/// Useful when DPD is unavailable and groups can't complete state transitions.
/// For example, when DPD is down during deletion, groups may be stuck in
/// "Creating" or "Deleting" state rather than being fully deleted.
pub(crate) async fn verify_group_deleted_or_in_states(
client: &ClientTestContext,
group_name: &str,
expected_states: &[&str],
) {
let groups_result =
nexus_test_utils::resource_helpers::objects_list_page_authz::<
MulticastGroup,
>(client, "/v1/multicast-groups")
.await;

let matching_groups: Vec<_> = groups_result
.items
.into_iter()
.filter(|g| g.identity.name == group_name)
.collect();

if !matching_groups.is_empty() {
// Group still exists - should be in one of the expected states
let actual_state = &matching_groups[0].state;
assert!(
expected_states.contains(&actual_state.as_str()),
"Group {group_name} should be in one of {expected_states:?} states, found: {actual_state}"
);
}
}

/// Wait for a multicast group to be deleted from DPD (dataplane) with reconciler activation.
///
/// This function waits for the DPD to report that the multicast group no longer exists
Expand Down
Loading
Loading