mirror of
https://github.com/utmapp/UTM.git
synced 2026-10-12 02:24:01 +00:00
Follow-up to the vmnet networking modes: - Rename "Shared Network (VM to VM)" to "NAT Network" (config value "NATNetwork", scripting term "nat network") so the picker does not offer two "Shared" modes that differ only by a suffix. - Request a fixed subnet per mode outside of the ranges vmnet hands out by default. Those ranges are also used by NAT attachments and QEMU, so guest addresses depended on what else was running whenever the network was (re)created. Fall back to a vmnet chosen subnet when ours is taken. - Show the mode description with DetailedSection. The bare Text row widened the form and clipped the labels and controls in the settings window. - Only require macOS 26 when a network is actually created, so a VM using one of these modes can still be edited and saved on older hosts. - Do not apply locale digit grouping to the vmnet error code. - Fold the validation flag into the existing one that skipped drives and leave the device unattached instead of using a NAT placeholder, remove the unused reverse mapping, key the networks by vmnet_mode_t, and isolate the manager to the main actor in place of a lock with no concurrent users. Use .1 as the host-side address within each preferred /24. As reproduced in PR #7865, vmnet accepts .0 during network creation but the interface fails later at startup. Assisted-by: Claude:claude-fable-5-1 Assisted-by: ChatGPT:GPT-6-Astra-Pro
91 lines
3.4 KiB
Swift
91 lines
3.4 KiB
Swift
//
|
|
// Copyright © 2021 osy. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
import SwiftUI
|
|
import Virtualization
|
|
|
|
struct VMConfigAppleNetworkingView: View {
|
|
@Binding var config: UTMAppleConfigurationNetwork
|
|
@EnvironmentObject private var data: UTMData
|
|
@State private var newMacAddress: String?
|
|
|
|
var body: some View {
|
|
Form {
|
|
if let modeDescription = modeDescription {
|
|
DetailedSection("", description: modeDescription) {
|
|
VMConfigConstantPicker("Network Mode", selection: $config.mode)
|
|
}
|
|
} else {
|
|
VMConfigConstantPicker("Network Mode", selection: $config.mode)
|
|
}
|
|
HStack {
|
|
TextField("MAC Address", text: $newMacAddress.bound, onCommit: {
|
|
commitMacAddress()
|
|
})
|
|
.onAppear {
|
|
newMacAddress = config.macAddress
|
|
}
|
|
Button("Random") {
|
|
let random = VZMACAddress.randomLocallyAdministered().string
|
|
newMacAddress = random
|
|
commitMacAddress()
|
|
}
|
|
}
|
|
if config.mode == .bridged {
|
|
Section(header: Text("Bridged Settings")) {
|
|
Picker("Interface", selection: $config.bridgeInterface) {
|
|
Text("Automatic")
|
|
.tag(nil as String?)
|
|
ForEach(VZBridgedNetworkInterface.networkInterfaces, id: \.identifier) { interface in
|
|
Text(interface.localizedDisplayName.map { "\($0) (\(interface.identifier))" } ?? interface.identifier)
|
|
.tag(interface.identifier as String?)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private var modeDescription: LocalizedStringKey? {
|
|
switch config.mode {
|
|
case .natNetwork: return "Virtual machines using this mode in the same UTM app can connect to each other and access the internet through your Mac."
|
|
case .host: return "Virtual machines using this mode in the same UTM app can connect to each other and your Mac. This network does not provide internet access."
|
|
default: return nil
|
|
}
|
|
}
|
|
|
|
private func commitMacAddress() {
|
|
guard let macAddress = newMacAddress else {
|
|
return
|
|
}
|
|
if let _ = VZMACAddress(string: macAddress) {
|
|
config.macAddress = macAddress
|
|
} else {
|
|
data.busyWork {
|
|
throw NSLocalizedString("Invalid MAC address.", comment: "VMConfigAppleNetworkingView")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct VMConfigAppleNetworkingView_Previews: PreviewProvider {
|
|
@State static private var config = UTMAppleConfigurationNetwork()
|
|
|
|
static var previews: some View {
|
|
VMConfigAppleNetworkingView(config: $config)
|
|
}
|
|
}
|