@@ -24,7 +24,6 @@ import Foundation
2424import ContainerizationExtras
2525import SystemPackage
2626import Virtualization
27- import vmnet
2827
2928/// A manager for creating and running containers.
3029/// Supports container networking options.
@@ -37,184 +36,6 @@ public struct ContainerManager: Sendable {
3736 self . imageStore. path. appendingPathComponent ( " containers " )
3837 }
3938
40- /// A network that can allocate and release interfaces for use with containers.
41- public protocol Network : Sendable {
42- mutating func create( _ id: String ) throws -> Interface ?
43- mutating func release( _ id: String ) throws
44- }
45-
46- /// A network backed by vmnet on macOS.
47- @available ( macOS 26 . 0 , * )
48- public struct VmnetNetwork : Network {
49- private var allocator : Allocator
50- // `reference` isn't used concurrently.
51- nonisolated ( unsafe) private let reference : vmnet_network_ref
52-
53- /// The IPv4 subnet of this network.
54- public let subnet : CIDRv4
55-
56- /// The IPv4 gateway address of this network.
57- public var ipv4Gateway : IPv4Address {
58- subnet. gateway
59- }
60-
61- struct Allocator : Sendable {
62- private let addressAllocator : any AddressAllocator < UInt32 >
63- private let cidr : CIDRv4
64- private var allocations : [ String : UInt32 ]
65-
66- init ( cidr: CIDRv4 ) throws {
67- self . cidr = cidr
68- self . allocations = . init( )
69- let size = Int ( cidr. upper. value - cidr. lower. value - 3 )
70- self . addressAllocator = try UInt32 . rotatingAllocator (
71- lower: cidr. lower. value + 2 ,
72- size: UInt32 ( size)
73- )
74- }
75-
76- mutating func allocate( _ id: String ) throws -> CIDRv4 {
77- if allocations [ id] != nil {
78- throw ContainerizationError ( . exists, message: " allocation with id \( id) already exists " )
79- }
80- let index = try addressAllocator. allocate ( )
81- allocations [ id] = index
82- let ip = IPv4Address ( index)
83- return try CIDRv4 ( ip, prefix: cidr. prefix)
84- }
85-
86- mutating func release( _ id: String ) throws {
87- if let index = self . allocations [ id] {
88- try addressAllocator. release ( index)
89- allocations. removeValue ( forKey: id)
90- }
91- }
92- }
93-
94- /// A network interface supporting the vmnet_network_ref.
95- public struct Interface : Containerization . Interface , VZInterface , Sendable {
96- public let ipv4Address : CIDRv4
97- public let ipv4Gateway : IPv4Address ?
98- public let macAddress : MACAddress ?
99- public let mtu : UInt32
100-
101- // `reference` isn't used concurrently.
102- nonisolated ( unsafe) private let reference : vmnet_network_ref
103-
104- public init (
105- reference: vmnet_network_ref ,
106- ipv4Address: CIDRv4 ,
107- ipv4Gateway: IPv4Address ,
108- macAddress: MACAddress ? = nil ,
109- mtu: UInt32 = 1500
110- ) {
111- self . ipv4Address = ipv4Address
112- self . ipv4Gateway = ipv4Gateway
113- self . macAddress = macAddress
114- self . mtu = mtu
115- self . reference = reference
116- }
117-
118- /// Returns the underlying `VZVirtioNetworkDeviceConfiguration`.
119- public func device( ) throws -> VZVirtioNetworkDeviceConfiguration {
120- let config = VZVirtioNetworkDeviceConfiguration ( )
121- if let macAddress = self . macAddress {
122- guard let mac = VZMACAddress ( string: macAddress. description) else {
123- throw ContainerizationError ( . invalidArgument, message: " invalid mac address \( macAddress) " )
124- }
125- config. macAddress = mac
126- }
127- config. attachment = VZVmnetNetworkDeviceAttachment ( network: self . reference)
128- return config
129- }
130- }
131-
132- /// Creates a new network.
133- /// - Parameter subnet: The subnet to use for this network.
134- public init ( subnet: CIDRv4 ? = nil ) throws {
135- var status : vmnet_return_t = . VMNET_FAILURE
136- guard let config = vmnet_network_configuration_create ( . VMNET_SHARED_MODE, & status) else {
137- throw ContainerizationError ( . unsupported, message: " failed to create vmnet config with status \( status) " )
138- }
139-
140- vmnet_network_configuration_disable_dhcp ( config)
141-
142- if let subnet {
143- try Self . configureSubnet ( config, subnet: subnet)
144- }
145-
146- guard let ref = vmnet_network_create ( config, & status) , status == . VMNET_SUCCESS else {
147- throw ContainerizationError ( . unsupported, message: " failed to create vmnet network with status \( status) " )
148- }
149-
150- let cidr = try Self . getSubnet ( ref)
151-
152- self . allocator = try . init( cidr: cidr)
153- self . subnet = cidr
154- self . reference = ref
155- }
156-
157- /// Returns a new interface for use with a container.
158- /// - Parameter id: The container ID.
159- public mutating func create( _ id: String ) throws -> Containerization . Interface ? {
160- let ipv4Address = try allocator. allocate ( id)
161- return Self . Interface (
162- reference: self . reference,
163- ipv4Address: ipv4Address,
164- ipv4Gateway: self . ipv4Gateway,
165- )
166- }
167-
168- /// Returns a new interface for use with a container with a custom MTU.
169- /// - Parameters:
170- /// - id: The container ID.
171- /// - mtu: The MTU for the interface.
172- public mutating func create( _ id: String , mtu: UInt32 ) throws -> Containerization . Interface ? {
173- let ipv4Address = try allocator. allocate ( id)
174- return Self . Interface (
175- reference: self . reference,
176- ipv4Address: ipv4Address,
177- ipv4Gateway: self . ipv4Gateway,
178- mtu: mtu
179- )
180- }
181-
182- /// Performs cleanup of an interface.
183- /// - Parameter id: The container ID.
184- public mutating func release( _ id: String ) throws {
185- try allocator. release ( id)
186- }
187-
188- private static func getSubnet( _ ref: vmnet_network_ref ) throws -> CIDRv4 {
189- var subnet = in_addr ( )
190- var mask = in_addr ( )
191- vmnet_network_get_ipv4_subnet ( ref, & subnet, & mask)
192-
193- let sa = UInt32 ( bigEndian: subnet. s_addr)
194- let mv = UInt32 ( bigEndian: mask. s_addr)
195-
196- let lower = IPv4Address ( sa & mv)
197- let upper = IPv4Address ( lower. value + ~ mv)
198-
199- return try CIDRv4 ( lower: lower, upper: upper)
200- }
201-
202- private static func configureSubnet( _ config: vmnet_network_configuration_ref , subnet: CIDRv4 ) throws {
203- let gateway = subnet. gateway
204-
205- var ga = in_addr ( )
206- inet_pton ( AF_INET, gateway. description, & ga)
207-
208- let mask = IPv4Address ( subnet. prefix. prefixMask32)
209- var ma = in_addr ( )
210- inet_pton ( AF_INET, mask. description, & ma)
211-
212- guard vmnet_network_configuration_set_ipv4_subnet ( config, & ga, & ma) == . VMNET_SUCCESS else {
213- throw ContainerizationError ( . internalError, message: " failed to set subnet \( subnet) for network " )
214- }
215- }
216- }
217-
21839 /// Create a new manager with the provided kernel, initfs mount, image store
21940 /// and optional network implementation. This will use a Virtualization.framework
22041 /// backed VMM implicitly.
@@ -475,7 +296,7 @@ public struct ContainerManager: Sendable {
475296 if let imageConfig {
476297 config. process = . init( from: imageConfig)
477298 }
478- if networking, let interface = try self . network? . create ( id) {
299+ if networking, let interface = try self . network? . createInterface ( id) {
479300 config. interfaces = [ interface]
480301 guard let gateway = interface. ipv4Gateway else {
481302 throw ContainerizationError (
@@ -494,7 +315,7 @@ public struct ContainerManager: Sendable {
494315 ///
495316 /// - Parameter id: The container ID.
496317 public mutating func releaseNetwork( _ id: String ) throws {
497- try self . network? . release ( id)
318+ try self . network? . releaseInterface ( id)
498319 }
499320
500321 /// Releases network resources and removes all files for a container.
0 commit comments