Skip to content
Open
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
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ arcbox-fleet-control-proto = { version = "0.6.3", path = "fleet/arcbox-fleet-con
arcbox-docker = { version = "0.6.3", path = "app/arcbox-docker" } # x-release-please-version
# Pinned to app/arcbox-helper's own version (not workspace.package). Do not
# attach x-release-please-version — helper releases are manual.
arcbox-helper = { version = "1.0.2", path = "app/arcbox-helper" }
arcbox-helper = { version = "1.0.3", path = "app/arcbox-helper" }
arcbox-core = { version = "0.6.3", path = "app/arcbox-core" } # x-release-please-version
arcbox-api = { version = "0.6.3", path = "app/arcbox-api" } # x-release-please-version
arcbox-migration = { version = "0.6.3", path = "app/arcbox-migration" } # x-release-please-version
Expand Down
10 changes: 5 additions & 5 deletions app/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ must name `abctl`.
e2e) may use — never log-grep or sleep. Fatal startup failures MUST call
`SetupState::set_failed` before exit (200ms flush grace, `main.rs`) so
clients see the cause instead of a bare disconnect. Route-install state is
mirrored into `SetupState.route_installed` by `services::route_status_loop`
(`ContainerRouteInstalled` sets, `MachineStopped` clears) — WHY: VM
restarts install the route outside the cold-start path that sets the flag
directly, so without the bridge the flag goes stale until the next daemon
restart.
exclusively owned by the `container_route` controller. It follows System
VM lifecycle and kernel route changes, caches bridge `{name, ifindex}` by VM
generation, and publishes the result through `SetupState.route_installed`.
Never add a second writer — WHY: competing lifecycle and polling paths can
publish stale state after the VM or bridge identity changes.
- **A `SetupStatus.Phase` value that nothing publishes is invisible as a
gap** — it simply never arrives, so a client waits forever or reports a
plausible zero. Declaring a phase in `api.proto` therefore obliges you to
Expand Down
1 change: 0 additions & 1 deletion app/arcbox-api/src/connect/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,6 @@ mod tests {
#[test]
fn ignores_non_machine_events() {
assert!(to_machine_event(&Event::VmStarted { id: "vm".into() }).is_none());
assert!(to_machine_event(&Event::ContainerRouteInstalled { name: "m".into() }).is_none());
}

#[test]
Expand Down
20 changes: 16 additions & 4 deletions app/arcbox-core/src/bridge_discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,20 @@
use std::ffi::CString;

/// Information about a bridge interface suitable for container routing.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BridgeTarget {
/// Interface name (e.g. "bridge104").
pub name: String,
/// Interface index (from `if_nametoindex`).
pub ifindex: u32,
pub ifindex: u16,
}

impl BridgeTarget {
/// Returns whether this name still identifies the same kernel interface.
#[must_use]
pub fn is_current(&self) -> bool {
if_nametoindex(&self.name) == Some(self.ifindex)
}
}

/// Resolve a VM bridge MAC to a bridge interface.
Expand Down Expand Up @@ -50,11 +58,15 @@ pub fn find_bridge_with_vmenet() -> Option<(String, String)> {
None
}

fn if_nametoindex(name: &str) -> Option<u32> {
fn if_nametoindex(name: &str) -> Option<u16> {
let cname = CString::new(name).ok()?;
// SAFETY: if_nametoindex is a standard POSIX function with a valid C string.
let idx = unsafe { libc::if_nametoindex(cname.as_ptr()) };
if idx == 0 { None } else { Some(idx) }
if idx == 0 {
None
} else {
u16::try_from(idx).ok()
}
}

#[cfg(test)]
Expand Down
2 changes: 0 additions & 2 deletions app/arcbox-core/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ pub enum Event {
MachineStopped { name: String },
/// Machine removed (record and disks deleted).
MachineRemoved { name: String },
/// Container subnet route installed on the host for a machine's bridge NIC.
ContainerRouteInstalled { name: String },
}

/// Event bus for system-wide event distribution.
Expand Down
6 changes: 3 additions & 3 deletions app/arcbox-core/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -743,14 +743,14 @@ impl MachineManager {
&self.vm_manager
}

/// Returns the vmnet bridge interface name for a machine's VM.
/// Returns the vmnet bridge identity for a machine's VM.
///
/// Only available when the `vmnet` feature is enabled and the VM is running.
#[cfg(all(target_os = "macos", feature = "vmnet"))]
pub fn vmnet_bridge_name(&self, name: &str) -> Option<String> {
pub fn vmnet_bridge_target(&self, name: &str) -> Option<crate::bridge_discovery::BridgeTarget> {
let machines = self.machines.read().ok()?;
let machine = machines.get(name)?;
self.vm_manager.vmnet_bridge_name(&machine.vm_id)
self.vm_manager.vmnet_bridge_target(&machine.vm_id)
}

/// Returns the bridge NIC MAC address for a machine's VM.
Expand Down
Loading
Loading