How Apple Container Integrates with vmnet for macOS Networking: A Technical Deep Dive

Apple container leverages the macOS vmnet framework through the container-network-vmnet XPC helper plugin to create virtual networks, allocate IP addresses from a default 192.168.64.1/24 subnet, and attach container namespaces to vmnet interfaces using the native C API.

The apple/container project provides Linux container support on macOS by integrating with the kernel-level vmnet framework for virtual network management. This apple container vmnet integration relies on a specialized XPC service that bridges the Swift-based container runtime with the underlying vmnet APIs, handling everything from network creation to IP address allocation and interface wiring.

The vmnet Integration Architecture

The networking stack is split between a privileged XPC helper and the container runtime. The helper manages the lifecycle of vmnet networks, while the runtime requests allocations and attaches containers to these virtual interfaces.

  • XPC Helper (container-network-vmnet): Runs as a privileged service to create vmnet networks and manage IP reservations.
  • Network Strategies: Two distinct approaches handle reserved networks versus standard container networks.
  • Runtime Wiring: The Linux container runtime receives network attachments via XPC and links them to the container's network namespace.

XPC Helper and Network Creation

The heart of the integration lives in Sources/Plugins/NetworkVmnet/NetworkVmnetHelper.swift. This XPC service initializes vmnet networks by calling vmnet_network_configuration_create followed by vmnet_network_create or vmnet_network_create_with_serialization for reserved networks.

In Sources/Services/NetworkVmnet/Server/ReservedVmnetNetwork.swift, the implementation configures the IPv4 subnet using vmnet_network_configuration_set_ipv4_subnet and optionally sets IPv6 prefixes with vmnet_network_configuration_set_ipv6_prefix. The code explicitly disables DHCP via vmnet_network_configuration_disable_dhcp() since the helper manages IP allocation directly.

The network reference (vmnet_network_ref) is serialized using vmnet_network_copy_serialization to persist the configuration across container restarts, ensuring that the virtual network survives individual container lifecycles.

Interface Strategies: Reserved vs Nonisolated

The codebase implements two distinct strategies for vmnet network attachment:

ReservedInterfaceStrategy (found in Sources/Services/NetworkVmnet/Server/ReservedVmnetNetwork.swift): Used for reserved networks that require persistent configuration and serialization. This strategy calls vmnet_network_create_with_serialization to restore or create a network with specific parameters.

NonisolatedInterfaceStrategy (located in Sources/Services/RuntimeLinux/Server/NonisolatedInterfaceStrategy.swift): Handles standard container networks without persistence requirements. It uses the standard vmnet_network_create API and configures the mode—either VMNET_HOST_MODE for host-only networking or VMNET_SHARED_MODE for NAT-backed connectivity.

Both strategies communicate with the same XPC helper but differ in how they allocate and maintain the underlying vmnet_network_ref.

Container Runtime Wiring

When a container launches, the runtime requests a network allocation from the helper via the container-network-vmnet allocate command. The helper returns an XPC message containing:

  • Hostname: The DNS name for the container
  • IP Address: Assigned from the 192.168.64.0/24 range (e.g., 192.168.64.2/24)
  • Gateway: Typically 192.168.64.1
  • Network ID: The vmnet network identifier (usually "default")

The runtime then creates a virtual network interface in the container's Linux network namespace and wires it to the vmnet attachment. This process is visible in the helper logs:

container-network-vmnet: allocated attachment [hostname=my-web-server.test.] \
  [address=192.168.64.2/24] [gateway=192.168.64.1] [id=default]

CLI and System Startup Integration

The Sources/ContainerCommands/Network/NetworkCreate.swift file handles the container network create command, which forwards the --plugin container-network-vmnet flag to the helper. While this is the default plugin, explicit specification ensures the vmnet backend is used.

System initialization triggers network creation automatically:


# Creates the default vmnet network on first run

container system start

The first container start causes the helper to instantiate the vmnet network named "default" if it does not already exist. Subsequent containers receive allocations from this existing network rather than creating new virtual infrastructure.

macOS 15 Constraints and Limitations

According to the technical documentation in the repository, several important constraints govern the apple container vmnet integration on macOS 15:

  • Single Network Limit: macOS 15 supports only a single shared VMnet network. The --network flag is rejected if attempting to create additional networks.
  • Container Isolation: The VMnet framework isolates each container's NIC, meaning container-to-container communication is not supported on macOS 15. Each container can reach the host and external networks (in shared mode) but cannot directly address other containers.
  • Subnet Synchronization: All containers share the default 192.168.64.1/24 network. If the network helper and VMnet framework disagree on subnet configuration, containers may experience connectivity loss.

Practical Configuration Examples

Start the container system to initialize the default vmnet network:

container system start

Verify the network is active and inspect allocations:

container network list

Run a container using the default vmnet network (no plugin flag required as it is the default):

container run -it --name demo alpine sh

Inside the container, verify the vmnet-assigned IP:

ip addr show eth0

# Expected output includes: inet 192.168.64.2/24 ...

Summary

  • The container-network-vmnet XPC helper in Sources/Plugins/NetworkVmnet/NetworkVmnetHelper.swift manages vmnet network lifecycle and IP allocation.
  • Network creation uses vmnet_network_create or vmnet_network_create_with_serialization with explicit DHCP disabling via vmnet_network_configuration_disable_dhcp().
  • Two strategies—ReservedInterfaceStrategy and NonisolatedInterfaceStrategy—handle different persistence and isolation requirements.
  • Containers receive IP addresses from the 192.168.64.0/24 subnet with the gateway at 192.168.64.1.
  • macOS 15 limits deployments to a single vmnet network and does not support container-to-container traffic.

Frequently Asked Questions

How does the container runtime communicate with vmnet?

The runtime communicates through an XPC service called container-network-vmnet. This privileged helper translates high-level container network requests into vmnet framework API calls, creating network references and returning allocation details back to the runtime via XPC messages.

Why is DHCP disabled in the vmnet configuration?

The apple/container implementation disables DHCP using vmnet_network_configuration_disable_dhcp() because the XPC helper manages IP allocation directly. This prevents conflicts between the vmnet framework's DHCP server and the container project's IP address management, ensuring consistent address assignments from the 192.168.64.0/24 range.

Can I create multiple vmnet networks for different container groups?

On macOS 15, no. The current implementation only supports a single shared vmnet network named "default." Attempting to specify alternative networks via the --network flag results in rejection. All containers must share the same 192.168.64.1/24 subnet, though they remain isolated from each other at the network interface level.

What happens if the vmnet helper and the framework disagree on the subnet?

If the container-network-vmnet helper's configured subnet conflicts with the vmnet framework's actual network configuration, containers may lose network connectivity entirely. Both components must agree on the 192.168.64.1/24 default (or any custom configured subnet) for traffic to flow correctly between the container, host, and external networks.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →