How vphone-cli Handles Virtual Machine Networking: Architecture and Implementation
vphone-cli configures virtual machine networking using Apple's Virtualization.framework through a declarative manifest system that validates settings in VPhoneNetworking.swift and supports NAT, bridged, and disabled attachment modes.
vphone-cli is a Swift-based command-line tool that orchestrates Linux virtual machines on macOS using Apple's Virtualization.framework. The project implements a type-safe abstraction layer for VM networking that centralizes validation logic in the VPhoneCore module while delegating device instantiation to the framework's native APIs. Understanding how vphone-cli handles networking requires examining three tightly-coupled components that manage configuration parsing, validation, and runtime injection.
Core Architecture Components
VPhoneNetworking.swift
Located at sources/VPhoneCore/VPhoneNetworking.swift, this file contains the central networking orchestrator. It exposes static methods that bridge the gap between user-facing configuration strings and concrete VZVirtioNetworkDeviceConfiguration objects.
Key responsibilities include:
availableBridgeInterfaces()– Discovers host network interfaces suitable for bridging viaVZBridgedNetworkInterface.networkInterfaces(lines 42-67)makeNetworkDevice()– Constructs the appropriate network attachment based on theNetworkModeenum, returningVZNATNetworkDeviceAttachment,VZBridgedNetworkDeviceAttachment, ornil(lines 92-116)merge()– Combines existing manifest configuration with CLI-provided overrides to produce a validatedNetworkConfig
VPhoneVirtualMachine.swift
The runtime component lives in sources/vphone-cli/VPhoneVirtualMachine.swift. During initialization (around lines 87-92), this class loads the persisted networkConfig from the VM manifest, invokes VPhoneNetworking.makeNetworkDevice(), and injects the resulting device into the VZVirtualMachineConfiguration.networkDevices array.
If networking is disabled, makeNetworkDevice() returns nil, resulting in an empty networkDevices array and a VM with no virtual NIC.
VPhoneVMCLI.swift
The user interface layer in sources/vphone-cli/VPhoneVMCLI.swift exposes the --network and --bridge-interface flags. It translates raw string arguments (like "bridged" or "nat") into the NetworkMode enum (.nat, .bridged, .off) and calls VPhoneBundleOps.updateConfig to persist changes to the manifest (lines 38-66).
Network Modes Explained
NAT Mode (Default)
When NetworkConfig.mode is set to .nat, makeNetworkDevice() returns a VZVirtioNetworkDeviceConfiguration initialized with VZNATNetworkDeviceAttachment. This mode requires no additional configuration; macOS automatically handles IP address assignment and routes VM traffic through the host's internet connection using Network Address Translation.
Bridged Mode
Bridged networking requires a valid host interface name (e.g., en0). The implementation calls resolveBridgeInterface() to select the requested, saved, or first available bridge, then constructs a VZBridgedNetworkDeviceAttachment(interface:) instance. In this mode, the VM appears as a distinct host on the local Ethernet segment, receiving its own IP address from the network's DHCP server rather than sharing the host's NAT layer.
Disabled Mode
Setting the mode to .off causes makeNetworkDevice() to return nil. Consequently, config.networkDevices remains empty, and the virtual machine boots with no network connectivity.
Host-Only Limitations
The framework explicitly blocks host-only networking. If selected, the code throws VPhoneNetworkingError.hostOnlyUnsupported because Apple's Virtualization.framework does not currently provide a host-only network attachment API.
Validation and Error Handling
The networking subsystem implements strict validation to prevent misconfiguration:
bridgeInterfaceNotFound– Thrown when the user specifies a bridge interface thatavailableBridgeInterfaces()cannot locatenoBridgeInterfaces– Thrown when the host system has noVZBridgedNetworkInterfaceinstances availablebridgeInterfaceWithoutBridgedMode– Thrown when--bridge-interfaceis provided without explicitly setting--network bridged
All errors conform to CustomStringConvertible to provide human-readable messages in the CLI output (defined in VPhoneNetworking.swift lines 6-17).
Runtime Configuration Flow
The declarative configuration follows this execution path:
- CLI Invocation – User executes
vphone vm config myVM --network bridged --bridge-interface en0 - Option Parsing –
VPhoneVMCLI.swiftconverts flags toNetworkMode.bridgedand validates syntax - Config Merge –
VPhoneBundleOps.updateConfigcallsVPhoneNetworking.merge()to reconcile new settings with the existing manifest - Persistence – The updated
NetworkConfigis written to the VM bundle's manifest - Boot Injection – When the VM starts,
VPhoneVirtualMachine.init(options:)loads the manifest and callsmakeNetworkDevice() - Device Attachment – The resulting NIC (or
nil) is assigned toconfig.networkDevicesbefore the VM launches
Practical Code Examples
Creating a NAT configuration:
import VPhoneCore
let config = VPhoneVirtualMachineManifest.NetworkConfig(mode: .nat, macAddress: "")
let device = try VPhoneNetworking.makeNetworkDevice(config)
// Returns VZVirtioNetworkDeviceConfiguration configured with VZNATNetworkDeviceAttachment
Configuring bridged networking on a specific interface:
let bridgedConfig = try VPhoneNetworking.merge(
into: VPhoneVirtualMachineManifest.NetworkConfig.default,
mode: .bridged,
bridgeInterface: "en0"
)
let device = try VPhoneNetworking.makeNetworkDevice(bridgedConfig)
// Returns device configured with VZBridgedNetworkDeviceAttachment
Disabling network access entirely:
let offConfig = VPhoneVirtualMachineManifest.NetworkConfig(mode: .off, macAddress: "")
let device = try VPhoneNetworking.makeNetworkDevice(offConfig)
// Returns nil; config.networkDevices will be empty
Summary
- vphone-cli implements networking through three components:
VPhoneNetworkingfor validation,VPhoneVirtualMachinefor runtime injection, andVPhoneVMCLIfor user interaction - Three modes are supported: NAT (default via
VZNATNetworkDeviceAttachment), bridged (viaVZBridgedNetworkDeviceAttachment), and disabled - Validation occurs centrally in
VPhoneNetworking.swiftviamerge()andmakeNetworkDevice(), ensuring CLI configuration and VM boot use identical logic - Host-only networking is unsupported due to Virtualization.framework API limitations
- File locations: Core logic resides in
sources/VPhoneCore/VPhoneNetworking.swiftandsources/vphone-cli/VPhoneVirtualMachine.swift
Frequently Asked Questions
What network modes does vphone-cli support?
vphone-cli supports NAT (the default), bridged, and disabled networking modes. NAT uses macOS internet sharing to route traffic, bridged mode attaches the VM directly to a physical host interface like en0, and disabled mode removes all networking hardware. Host-only networking is explicitly unsupported; attempting to configure it triggers VPhoneNetworkingError.hostOnlyUnsupported because Apple's Virtualization.framework lacks the necessary attachment type.
How does vphone-cli validate bridge interfaces?
The framework validates interfaces through VPhoneNetworking.availableBridgeInterfaces(), which queries VZBridgedNetworkInterface.networkInterfaces to enumerate host bridges. If the specified interface is missing, the code throws bridgeInterfaceNotFound. If the system has no bridge-capable interfaces, it throws noBridgeInterfaces. The parser also enforces that --bridge-interface can only be used when --network bridged is explicitly set, throwing bridgeInterfaceWithoutBridgedMode otherwise.
Where is the network device actually attached to the VM?
The attachment occurs in sources/vphone-cli/VPhoneVirtualMachine.swift during the VM initialization sequence. After loading the manifest's networkConfig, the initializer calls VPhoneNetworking.makeNetworkDevice() and appends the result to the VZVirtualMachineConfiguration.networkDevices array. This happens before the virtual machine is instantiated, ensuring the network hardware is present at boot time.
Can I change networking settings while the VM is running?
No. vphone-cli uses a declarative configuration model where settings are persisted to the VM's manifest file. Network configuration is read once during VPhoneVirtualMachine initialization, and Apple's Virtualization.framework does not support hot-plugging network devices after the VM has started. To change networking, you must stop the VM, run vphone vm config to update the manifest, and then start the VM again.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →