How Networks Function Within Container: macOS vmnet Networking Explained
Container networking leverages the macOS vmnet framework and XPC helpers to create isolated virtual networks, automatically assigning IP addresses to containers through the container-network-vmnet helper.
The apple/container repository implements a sophisticated networking stack that bridges macOS virtualization capabilities with container workloads. Understanding how networks function within Container requires examining the interaction between the vmnet framework, XPC-based helper services, and the Swift APIs exposed to users. This architecture enables seamless network isolation while maintaining the performance characteristics of native macOS virtualization.
Core Architecture: The vmnet Framework and XPC Helpers
When container system start executes, the container-apiserver launch agent initializes three critical helper processes that orchestrate container lifecycle and networking.
The Three Core Services
The system relies on distinct helpers for specialized functions:
container-core-images– Manages container images and layer storagecontainer-network-vmnet– Implements the virtual network interface using the vmnet frameworkcontainer-runtime-linux– Executes and monitors container processes
The network helper creates a vmnet network named default that automatically attaches to every container unless overridden by specific configuration.
Network Isolation
Each network operates in complete isolation from others. Containers sharing the same network can communicate directly, while cross-network traffic is prohibited. This isolation is enforced at the vmnet framework level.
Note: On macOS 15, the vmnet framework supports only a single network, which restricts container network commands on that version.
Network Configuration and Definition
Networks are defined by the NetworkConfiguration struct located in Sources/ContainerResource/Network/NetworkConfiguration.swift.
Configuration Structure
The struct encapsulates:
- Name – Unique network identifier
- Mode – Either
natorhostOnly - Subnets – Optional IPv4 (
CIDRv4) and IPv6 (CIDRv6) specifications - Labels – Metadata via
ResourceLabels - Plugin – Always
container-network-vmnetfor the default implementation - Options – Plugin-specific key-value pairs
Validation and Serialization
The NetworkConfiguration validates network names and serializes to JSON for transmission via XPC. This ensures type safety across the client-helper boundary defined in NetworkRoutes and NetworkKeys.
The NetworkClient: XPC Communication Layer
The NetworkClient class in Sources/Services/Network/Client/NetworkClient.swift provides the Swift interface for network operations.
Establishing Persistent Connections
The connect() method opens a persistent XPC session that must remain active for the duration of any network allocations. Closing this session automatically releases all associated IP allocations.
Allocating Network Attachments
The allocate(hostname:macAddress:on:) method requests IP and MAC address assignment:
import ContainerNetworkClient
import ContainerXPC
let client = NetworkClient(id: "foo", plugin: "container-network-vmnet")
let session = client.connect()
let (attachment, _) = try await client.allocate(
hostname: "my-web-server.test.",
macAddress: MACAddress("02:42:ac:11:00:02"),
on: session
)
print("Container received IP: \(attachment.address)")
The helper returns an Attachment value describing the network interface configuration.
Looking Up Existing Attachments
Query existing allocations using lookup(hostname:):
let client = NetworkClient(id: "foo", plugin: "container-network-vmnet")
if let attachment = try await client.lookup(hostname: "my-web-server.test.") {
print("Found IP: \(attachment.address)")
}
CLI Integration and Usage
The container network subcommands provide thin wrappers over the NetworkClient API, handling argument parsing and configuration building.
Creating Custom Networks
Create isolated networks with custom subnets and labels:
container network create foo \
--subnet 192.168.100.0/24 \
--subnet-v6 fd00:1234::/64 \
--label env=dev \
--option foo=bar
This command parses options into a NetworkConfiguration and invokes NetworkClient().create(configuration:) behind the scenes. The implementation resides in Sources/ContainerCommands/Network/NetworkCreate.swift.
Programmatic Network Creation
Create networks directly in Swift:
import ContainerResource
import ContainerNetworkClient
let labels = try ResourceLabels(["env": "dev"])
let options = ["foo": "bar"]
let config = try NetworkConfiguration(
name: "foo",
mode: .nat,
ipv4Subnet: CIDRv4("192.168.100.0/24"),
ipv6Subnet: CIDRv6("fd00:1234::/64"),
labels: labels,
plugin: "container-network-vmnet",
options: options
)
let client = NetworkClient()
let network = try await client.create(configuration: config)
print("Created network with ID: \(network.id)")
Inspecting Network State
Retrieve network details in JSON format:
container network inspect foo --format json
Runtime Behavior: IP Allocation and Lifecycle
When a container starts, the runtime helper passes the network name to container-network-vmnet via XPC messages. The helper then:
- Allocates an IP address from the network's CIDR range
- Updates the container's
/sys/class/net/eth0interface data - Records the attachment in internal state
The allocation persists until the XPC session closes (e.g., when the container stops), at which point the helper automatically releases the IP address back to the pool.
The NetworkVmnetHelper.swift file in Sources/Plugins/NetworkVmnet/ serves as the entry point for these XPC operations, handling the low-level vmnet framework interactions.
Summary
- Container networking relies on the macOS vmnet framework and the
container-network-vmnetXPC helper for virtual network implementation - NetworkClient in
Sources/Services/Network/Client/NetworkClient.swiftmanages persistent XPC connections and IP allocation throughallocate()andlookup()methods - NetworkConfiguration defines network properties including mode (
natorhostOnly), subnets, and labels, validated inSources/ContainerResource/Network/NetworkConfiguration.swift - Automatic cleanup occurs when XPC sessions close, releasing IP allocations without manual intervention
- macOS 15 limitation restricts the framework to a single network, disabling multiple network creation on that version
Frequently Asked Questions
How does Container handle IP address assignment?
Container uses the container-network-vmnet helper to allocate IP addresses dynamically from the network's defined CIDR range. When a container starts, the runtime requests an allocation via XPC, receiving an Attachment object containing the assigned IP and interface configuration. The helper updates the container's network interface files directly and automatically releases the address when the container stops and the XPC session terminates.
Can I use custom subnets when creating networks?
Yes. The NetworkConfiguration struct accepts optional ipv4Subnet and ipv6Subnet parameters using CIDRv4 and CIDRv6 types. You can specify these via the CLI using --subnet and --subnet-v6 flags, or programmatically when initializing NetworkConfiguration in Swift. The helper validates these ranges before allocation.
Why are container network commands unavailable on macOS 15?
The vmnet framework on macOS 15 supports only a single virtual network interface. Since Container's architecture expects the ability to create multiple isolated networks, the container network subcommands are disabled on this version to prevent configuration errors. Containers still receive network connectivity through the automatically created default network.
How do containers communicate across different networks?
Containers on different networks cannot communicate directly. The vmnet framework enforces isolation between networks at the virtualization layer. To enable communication, containers must reside on the same network, or traffic must route through a bridge container that attaches to multiple networks (though this requires specific configuration not available on macOS 15 due to single-network limitations).
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 →