Skip to content
This repository was archived by the owner on Oct 19, 2024. It is now read-only.

Commit 9f62857

Browse files
authored
Merge pull request #4 from saracen/nbd-support
added VZNetworkBlockDeviceStorageDeviceAttachment
2 parents 037df70 + 17ea5db commit 9f62857

File tree

5 files changed

+120
-11
lines changed

5 files changed

+120
-11
lines changed

example/macOS/main.go

+24-10
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ import (
1414
)
1515

1616
var install bool
17+
var nbdURL string
1718

1819
func init() {
1920
flag.BoolVar(&install, "install", false, "run command as install mode")
21+
flag.StringVar(&nbdURL, "nbd-url", "", "nbd url (e.g. nbd+unix:///export?socket=nbd.sock)")
2022
}
2123

2224
func main() {
@@ -142,21 +144,33 @@ func computeMemorySize() uint64 {
142144
}
143145

144146
func createBlockDeviceConfiguration(diskPath string) (*vz.VirtioBlockDeviceConfiguration, error) {
145-
// create disk image with 64 GiB
146-
if err := vz.CreateDiskImage(diskPath, 64*1024*1024*1024); err != nil {
147-
if !os.IsExist(err) {
148-
return nil, fmt.Errorf("failed to create disk image: %w", err)
147+
var attachment vz.StorageDeviceAttachment
148+
var err error
149+
150+
if nbdURL == "" {
151+
// create disk image with 64 GiB
152+
if err := vz.CreateDiskImage(diskPath, 64*1024*1024*1024); err != nil {
153+
if !os.IsExist(err) {
154+
return nil, fmt.Errorf("failed to create disk image: %w", err)
155+
}
149156
}
150-
}
151157

152-
diskImageAttachment, err := vz.NewDiskImageStorageDeviceAttachment(
153-
diskPath,
154-
false,
155-
)
158+
attachment, err = vz.NewDiskImageStorageDeviceAttachment(
159+
diskPath,
160+
false,
161+
)
162+
} else {
163+
attachment, err = vz.NewNetworkBlockDeviceStorageDeviceAttachment(
164+
nbdURL,
165+
10*time.Second,
166+
false,
167+
vz.DiskSynchronizationModeFull,
168+
)
169+
}
156170
if err != nil {
157171
return nil, err
158172
}
159-
return vz.NewVirtioBlockDeviceConfiguration(diskImageAttachment)
173+
return vz.NewVirtioBlockDeviceConfiguration(attachment)
160174
}
161175

162176
func createGraphicsDeviceConfiguration() (*vz.MacGraphicsDeviceConfiguration, error) {

osversion_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,10 @@ func TestAvailableVersion(t *testing.T) {
319319
_, err := NewDiskBlockDeviceStorageDeviceAttachment(nil, false, DiskSynchronizationModeFull)
320320
return err
321321
},
322+
"NewNetworkBlockDeviceStorageDeviceAttachment": func() error {
323+
_, err := NewNetworkBlockDeviceStorageDeviceAttachment("", 0, false, DiskSynchronizationModeFull)
324+
return err
325+
},
322326
}
323327
for name, fn := range cases {
324328
t.Run(name, func(t *testing.T) {

storage.go

+57
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ package vz
1212
import "C"
1313
import (
1414
"os"
15+
"time"
1516

1617
"github.com/Code-Hex/vz/v3/internal/objc"
1718
)
@@ -397,3 +398,59 @@ func NewDiskBlockDeviceStorageDeviceAttachment(file *os.File, readOnly bool, syn
397398
})
398399
return attachment, nil
399400
}
401+
402+
// NetworkBlockDeviceStorageDeviceAttachment is a storage device attachment that is backed by a
403+
// NBD (Network Block Device) server.
404+
//
405+
// Using this attachment requires the app to have the com.apple.security.network.client entitlement
406+
// because this attachment opens an outgoing network connection.
407+
//
408+
// For more information about the NBD URL format read:
409+
// https://github.com/NetworkBlockDevice/nbd/blob/master/doc/uri.md
410+
type NetworkBlockDeviceStorageDeviceAttachment struct {
411+
*pointer
412+
413+
*baseStorageDeviceAttachment
414+
}
415+
416+
var _ StorageDeviceAttachment = (*NetworkBlockDeviceStorageDeviceAttachment)(nil)
417+
418+
// NewNetworkBlockDeviceStorageDeviceAttachment creates a new network block device storage attachment from an NBD
419+
// Uniform Resource Indicator (URI) represented as a URL, timeout value, and read-only and synchronization modes
420+
// that you provide.
421+
//
422+
// - url is the NBD server URI. The format specified by https://github.com/NetworkBlockDevice/nbd/blob/master/doc/uri.md
423+
// - timeout is the duration for the connection between the client and server. When the timeout expires, an attempt to reconnect with the server takes place.
424+
// - forcedReadOnly if true forces the disk attachment to be read-only, regardless of whether or not the NBD server supports write requests.
425+
// - syncMode is one of the available DiskSynchronizationMode options.
426+
//
427+
// This is only supported on macOS 14 and newer, error will
428+
// be returned on older versions.
429+
func NewNetworkBlockDeviceStorageDeviceAttachment(url string, timeout time.Duration, forcedReadOnly bool, syncMode DiskSynchronizationMode) (*NetworkBlockDeviceStorageDeviceAttachment, error) {
430+
if err := macOSAvailable(14); err != nil {
431+
return nil, err
432+
}
433+
434+
nserrPtr := newNSErrorAsNil()
435+
436+
urlChar := charWithGoString(url)
437+
defer urlChar.Free()
438+
attachment := &NetworkBlockDeviceStorageDeviceAttachment{
439+
pointer: objc.NewPointer(
440+
C.newVZNetworkBlockDeviceStorageDeviceAttachment(
441+
urlChar.CString(),
442+
C.double(timeout.Seconds()),
443+
C.bool(forcedReadOnly),
444+
C.int(syncMode),
445+
&nserrPtr,
446+
),
447+
),
448+
}
449+
if err := newNSError(nserrPtr); err != nil {
450+
return nil, err
451+
}
452+
objc.SetFinalizer(attachment, func(self *NetworkBlockDeviceStorageDeviceAttachment) {
453+
objc.Release(self)
454+
})
455+
return attachment, nil
456+
}

virtualization_14.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515

1616
/* macOS 14 API */
1717
void *newVZNVMExpressControllerDeviceConfiguration(void *attachment);
18-
void *newVZDiskBlockDeviceStorageDeviceAttachment(int fileDescriptor, bool readOnly, int syncMode, void **error);
18+
void *newVZDiskBlockDeviceStorageDeviceAttachment(int fileDescriptor, bool readOnly, int syncMode, void **error);
19+
void *newVZNetworkBlockDeviceStorageDeviceAttachment(const char *url, double timeout, bool forcedReadOnly, int syncMode, void **error);

virtualization_14.m

+33
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,37 @@
5050
}
5151
#endif
5252
RAISE_UNSUPPORTED_MACOS_EXCEPTION();
53+
}
54+
55+
/*!
56+
@abstract Initialize a network block device storage attachment from an NBD URI.
57+
@param uri The NBD’s URI represented as a URL.
58+
@param timeout The timeout value in seconds for the connection between the client and server. When the timeout expires, an attempt to reconnect with the server takes place.
59+
@param forcedReadOnly If YES, the framework forces the disk attachment to be read-only, regardless of whether or not the NBD server supports write requests.
60+
@param synchronizationMode Defines how the disk synchronizes with the underlying storage when the guest operating system flushes data.
61+
@param error If not nil, assigned with the error if the initialization failed.
62+
@return An initialized `VZDiskBlockDeviceStorageDeviceAttachment` or nil if there was an error.
63+
@discussion
64+
The forcedReadOnly parameter affects how framework exposes the NBD client to the guest operating
65+
system by the storage controller. As part of the NBD protocol, the NBD server advertises whether
66+
or not the disk exposed by the NBD client is read-only during the handshake phase of the protocol.
67+
68+
Setting forcedReadOnly to YES forces the NBD client to show up as read-only to the guest
69+
regardless of whether or not the NBD server advertises itself as read-only.
70+
*/
71+
void *newVZNetworkBlockDeviceStorageDeviceAttachment(const char *uri, double timeout, bool forcedReadOnly, int syncMode, void **error)
72+
{
73+
#ifdef INCLUDE_TARGET_OSX_14
74+
if (@available(macOS 14, *)) {
75+
NSURL *url = [NSURL URLWithString:[NSString stringWithUTF8String:uri]];
76+
77+
return [[VZNetworkBlockDeviceStorageDeviceAttachment alloc]
78+
initWithURL:url
79+
timeout:(NSTimeInterval)timeout
80+
forcedReadOnly:(BOOL)forcedReadOnly
81+
synchronizationMode:(VZDiskSynchronizationMode)syncMode
82+
error:(NSError *_Nullable *_Nullable)error];
83+
}
84+
#endif
85+
RAISE_UNSUPPORTED_MACOS_EXCEPTION();
5386
}

0 commit comments

Comments
 (0)