@@ -23,11 +23,13 @@ struct UTMAppleConfigurationNetwork: Codable, Identifiable {
2323 enum NetworkMode : String , CaseIterable , QEMUConstant {
2424 case shared = " Shared "
2525 case bridged = " Bridged "
26+ case host = " Host "
2627
2728 var prettyValue : String {
2829 switch self {
2930 case . shared: return NSLocalizedString ( " Shared Network " , comment: " UTMAppleConfigurationNetwork " )
3031 case . bridged: return NSLocalizedString ( " Bridged (Advanced) " , comment: " UTMAppleConfigurationNetwork " )
32+ case . host: return NSLocalizedString ( " Host (Advanced) " , comment: " UTMAppleConfigurationNetwork " )
3133 }
3234 }
3335 }
@@ -40,12 +42,16 @@ struct UTMAppleConfigurationNetwork: Codable, Identifiable {
4042 /// In bridged mode this is the physical interface to bridge.
4143 var bridgeInterface : String ?
4244
45+ /// Network UUID to attach to in host mode
46+ var hostNetUuid : String ?
47+
4348 let id = UUID ( )
4449
4550 enum CodingKeys : String , CodingKey {
4651 case mode = " Mode "
4752 case macAddress = " MacAddress "
4853 case bridgeInterface = " BridgeInterface "
54+ case hostNetUuid = " HostNetUuid "
4955 }
5056
5157 init ( ) {
@@ -56,6 +62,7 @@ struct UTMAppleConfigurationNetwork: Codable, Identifiable {
5662 mode = try values. decode ( NetworkMode . self, forKey: . mode)
5763 macAddress = try values. decode ( String . self, forKey: . macAddress)
5864 bridgeInterface = try values. decodeIfPresent ( String . self, forKey: . bridgeInterface)
65+ hostNetUuid = try values. decodeIfPresent ( UUID . self, forKey: . hostNetUuid) ? . uuidString
5966 }
6067
6168 func encode( to encoder: Encoder ) throws {
@@ -65,6 +72,9 @@ struct UTMAppleConfigurationNetwork: Codable, Identifiable {
6572 if mode == . bridged {
6673 try container. encodeIfPresent ( bridgeInterface, forKey: . bridgeInterface)
6774 }
75+ if mode == . host {
76+ try container. encodeIfPresent ( hostNetUuid, forKey: . hostNetUuid)
77+ }
6878 }
6979
7080 init ? ( from config: VZNetworkDeviceConfiguration ) {
@@ -77,9 +87,26 @@ struct UTMAppleConfigurationNetwork: Codable, Identifiable {
7787 bridgeInterface = attachment. interface. identifier
7888 } else if let _ = virtioConfig. attachment as? VZNATNetworkDeviceAttachment {
7989 mode = . shared
80- } else {
81- return nil
90+ } else if #available( macOS 26 . 0 , * ) {
91+ if let attachment = virtioConfig. attachment as? VZVmnetNetworkDeviceAttachment {
92+ mode = . host
93+ var status : vmnet_return_t = . VMNET_SUCCESS
94+ guard let vmnetConfig = vmnet_network_copy_serialization ( attachment. network, & status) , status == . VMNET_SUCCESS else {
95+ return nil
96+ }
97+ if let uuidPtr = xpc_dictionary_get_uuid ( vmnetConfig, vmnet. vmnet_network_identifier_key) {
98+ let uuidBytes = UnsafeRawPointer ( uuidPtr) . assumingMemoryBound ( to: UInt8 . self)
99+ let uuid = UUID ( uuid: (
100+ uuidBytes [ 0 ] , uuidBytes [ 1 ] , uuidBytes [ 2 ] , uuidBytes [ 3 ] ,
101+ uuidBytes [ 4 ] , uuidBytes [ 5 ] , uuidBytes [ 6 ] , uuidBytes [ 7 ] ,
102+ uuidBytes [ 8 ] , uuidBytes [ 9 ] , uuidBytes [ 10 ] , uuidBytes [ 11 ] ,
103+ uuidBytes [ 12 ] , uuidBytes [ 13 ] , uuidBytes [ 14 ] , uuidBytes [ 15 ]
104+ ) )
105+ hostNetUuid = uuid. uuidString
106+ }
107+ }
82108 }
109+ return nil
83110 }
84111
85112 func vzNetworking( ) -> VZNetworkDeviceConfiguration ? {
@@ -109,7 +136,24 @@ struct UTMAppleConfigurationNetwork: Codable, Identifiable {
109136 let attachment = VZBridgedNetworkDeviceAttachment ( interface: found)
110137 config. attachment = attachment
111138 }
139+ case . host:
140+ if #available( macOS 26 . 0 , * ) {
141+ if let netUuid = hostNetUuid {
142+ let vmnetConfig = xpc_dictionary_create_empty ( )
143+ xpc_dictionary_set_uint64 ( vmnetConfig, vmnet. vmnet_operation_mode_key, UInt64 ( vmnet. vmnet_mode_t. VMNET_HOST_MODE. rawValue) )
144+ xpc_dictionary_set_uuid ( vmnetConfig, vmnet. vmnet_network_identifier_key, netUuid)
145+
146+ var status : vmnet_return_t = . VMNET_SUCCESS
147+ guard let vmnetNetwork = vmnet_network_create_with_serialization ( vmnetConfig, & status) , status == . VMNET_SUCCESS else {
148+ return nil
149+ }
150+
151+ let attachment = VZVmnetNetworkDeviceAttachment ( network: vmnetNetwork)
152+ config. attachment = attachment
153+ }
154+ }
112155 }
156+
113157 return config
114158 }
115159}
0 commit comments