qemu: support URI syntax for NBD

QEMU 1.3 and newer support an alternative URI-based syntax to specify
the location of an NBD server.  Libvirt can keep on using the old
syntax in general, but only the URI syntax supports IPv6 addresses.

The URI syntax also supports relative paths to Unix sockets.  These
should never be used but aren't explicitly blocked either by the parser,
so support it just in case.

The URI syntax is intentionally compatible with Gluster's, and the
code can be reused.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Paolo Bonzini 2013-02-25 18:44:25 +01:00 committed by Eric Blake
parent be2a15dd60
commit eebbb232e6
8 changed files with 154 additions and 29 deletions

View File

@ -2296,36 +2296,37 @@ no_memory:
}
static int
qemuParseGlusterString(virDomainDiskDefPtr def)
qemuParseDriveURIString(virDomainDiskDefPtr def, virURIPtr uri,
const char *scheme)
{
int ret = -1;
char *transp = NULL;
char *sock = NULL;
char *volimg = NULL;
virURIPtr uri = NULL;
if (!(uri = virURIParse(def->src))) {
return -1;
}
if (VIR_ALLOC(def->hosts) < 0)
goto no_memory;
if (STREQ(uri->scheme, "gluster")) {
def->hosts->transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
} else if (STRPREFIX(uri->scheme, "gluster+")) {
transp = strchr(uri->scheme, '+') + 1;
def->hosts->transport = virDomainDiskProtocolTransportTypeFromString(transp);
if (def->hosts->transport < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Invalid gluster transport type '%s'"), transp);
goto error;
}
} else {
transp = strchr(uri->scheme, '+');
if (transp)
*transp++ = 0;
if (!STREQ(uri->scheme, scheme)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Invalid transport/scheme '%s'"), uri->scheme);
goto error;
}
if (!transp) {
def->hosts->transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
} else {
def->hosts->transport = virDomainDiskProtocolTransportTypeFromString(transp);
if (def->hosts->transport < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Invalid %s transport type '%s'"), scheme, transp);
goto error;
}
}
def->nhosts = 0; /* set to 1 once everything succeeds */
if (def->hosts->transport != VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) {
@ -2351,11 +2352,16 @@ qemuParseGlusterString(virDomainDiskDefPtr def)
}
}
}
volimg = uri->path + 1; /* skip the prefix slash */
VIR_FREE(def->src);
def->src = strdup(volimg);
if (!def->src)
goto no_memory;
if (uri->path) {
volimg = uri->path + 1; /* skip the prefix slash */
VIR_FREE(def->src);
def->src = strdup(volimg);
if (!def->src)
goto no_memory;
} else {
VIR_FREE(def->src);
def->src = NULL;
}
def->nhosts = 1;
ret = 0;
@ -2373,6 +2379,17 @@ error:
goto cleanup;
}
static int
qemuParseGlusterString(virDomainDiskDefPtr def)
{
virURIPtr uri = NULL;
if (!(uri = virURIParse(def->src)))
return -1;
return qemuParseDriveURIString(def, uri, "gluster");
}
static int
qemuParseNBDString(virDomainDiskDefPtr disk)
{
@ -2380,6 +2397,14 @@ qemuParseNBDString(virDomainDiskDefPtr disk)
char *host, *port;
char *src;
virURIPtr uri = NULL;
if (strstr(disk->src, "://")) {
uri = virURIParse(disk->src);
if (uri)
return qemuParseDriveURIString(disk, uri, "nbd");
}
if (VIR_ALLOC(h) < 0)
goto no_memory;
@ -2436,7 +2461,8 @@ error:
}
static int
qemuBuildGlusterString(virDomainDiskDefPtr disk, virBufferPtr opt)
qemuBuildDriveURIString(virDomainDiskDefPtr disk, virBufferPtr opt,
const char *scheme)
{
int ret = -1;
int port = 0;
@ -2450,18 +2476,18 @@ qemuBuildGlusterString(virDomainDiskDefPtr disk, virBufferPtr opt)
};
if (disk->nhosts != 1) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("gluster accepts only one host"));
virReportError(VIR_ERR_INTERNAL_ERROR,
_("%s accepts only one host"), scheme);
return -1;
}
virBufferAddLit(opt, "file=");
transp = virDomainDiskProtocolTransportTypeToString(disk->hosts->transport);
if (virAsprintf(&tmpscheme, "gluster+%s", transp) < 0)
if (virAsprintf(&tmpscheme, "%s+%s", scheme, transp) < 0)
goto no_memory;
if (virAsprintf(&volimg, "/%s", disk->src) < 0)
if (disk->src && virAsprintf(&volimg, "/%s", disk->src) < 0)
goto no_memory;
if (disk->hosts->port) {
@ -2496,6 +2522,12 @@ no_memory:
goto cleanup;
}
static int
qemuBuildGlusterString(virDomainDiskDefPtr disk, virBufferPtr opt)
{
return qemuBuildDriveURIString(disk, opt, "gluster");
}
#define QEMU_DEFAULT_NBD_PORT "10809"
static int
@ -2509,6 +2541,13 @@ qemuBuildNBDString(virDomainDiskDefPtr disk, virBufferPtr opt)
return -1;
}
if ((disk->hosts->name && strchr(disk->hosts->name, ':'))
|| (disk->hosts->transport == VIR_DOMAIN_DISK_PROTO_TRANS_TCP
&& !disk->hosts->name)
|| (disk->hosts->transport == VIR_DOMAIN_DISK_PROTO_TRANS_UNIX
&& disk->hosts->socket && disk->hosts->socket[0] != '/'))
return qemuBuildDriveURIString(disk, opt, "nbd");
virBufferAddLit(opt, "file=nbd:");
switch (disk->hosts->transport) {
@ -7832,7 +7871,8 @@ qemuParseCommandLineDisk(virCapsPtr qemuCaps,
values[i] = NULL;
if (STRPREFIX(def->src, "/dev/"))
def->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
else if (STRPREFIX(def->src, "nbd:")) {
else if (STRPREFIX(def->src, "nbd:") ||
STRPREFIX(def->src, "nbd+")) {
def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
def->protocol = VIR_DOMAIN_DISK_PROTOCOL_NBD;
@ -7853,7 +7893,8 @@ qemuParseCommandLineDisk(virCapsPtr qemuCaps,
goto cleanup;
VIR_FREE(p);
} else if (STRPREFIX(def->src, "gluster")) {
} else if (STRPREFIX(def->src, "gluster:") ||
STRPREFIX(def->src, "gluster+")) {
def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
def->protocol = VIR_DOMAIN_DISK_PROTOCOL_GLUSTER;

View File

@ -186,6 +186,8 @@ mymain(void)
DO_TEST("disk-drive-cache-unsafe");
DO_TEST("disk-drive-network-nbd");
DO_TEST("disk-drive-network-nbd-export");
DO_TEST("disk-drive-network-nbd-ipv6");
DO_TEST("disk-drive-network-nbd-ipv6-export");
DO_TEST("disk-drive-network-nbd-unix");
DO_TEST("disk-drive-network-gluster");
DO_TEST("disk-drive-network-rbd");

View File

@ -0,0 +1,5 @@
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait \
-no-acpi -boot c -usb -drive file=/dev/HostVG/QEMUGuest1,if=ide,bus=0,unit=0 \
-drive 'file=nbd+tcp://[::1]:6000/bar,if=virtio,format=raw' -net none \
-serial none -parallel none

View File

@ -0,0 +1,33 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu</emulator>
<disk type='block' device='disk'>
<source dev='/dev/HostVG/QEMUGuest1'/>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<disk type='network' device='disk'>
<driver name='qemu' type='raw'/>
<source protocol='nbd' name='bar'>
<host name='::1' port='6000'/>
</source>
<target dev='vda' bus='virtio'/>
</disk>
<controller type='usb' index='0'/>
<controller type='ide' index='0'/>
<memballoon model='virtio'/>
</devices>
</domain>

View File

@ -0,0 +1,5 @@
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait \
-no-acpi -boot c -usb -drive file=/dev/HostVG/QEMUGuest1,if=ide,bus=0,unit=0 \
-drive 'file=nbd+tcp://[::1]:6000,if=virtio,format=raw' -net none \
-serial none -parallel none

View File

@ -0,0 +1,33 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory unit='KiB'>219136</memory>
<currentMemory unit='KiB'>219136</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/qemu</emulator>
<disk type='block' device='disk'>
<source dev='/dev/HostVG/QEMUGuest1'/>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<disk type='network' device='disk'>
<driver name='qemu' type='raw'/>
<source protocol='nbd'>
<host name='::1' port='6000'/>
</source>
<target dev='vda' bus='virtio'/>
</disk>
<controller type='usb' index='0'/>
<controller type='ide' index='0'/>
<memballoon model='virtio'/>
</devices>
</domain>

View File

@ -495,6 +495,10 @@ mymain(void)
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("disk-drive-network-nbd-export",
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("disk-drive-network-nbd-ipv6",
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("disk-drive-network-nbd-ipv6-export",
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("disk-drive-network-nbd-unix",
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("disk-drive-network-gluster",

View File

@ -171,6 +171,8 @@ mymain(void)
DO_TEST("disk-drive-cache-v1-none");
DO_TEST("disk-drive-network-nbd");
DO_TEST("disk-drive-network-nbd-export");
DO_TEST("disk-drive-network-nbd-ipv6");
DO_TEST("disk-drive-network-nbd-ipv6-export");
DO_TEST("disk-drive-network-nbd-unix");
DO_TEST("disk-scsi-device");
DO_TEST("disk-scsi-vscsi");