[libvirt] [PATCH] qemu: escape ipv6 for rbd network disk hosts

Hosts for rbd are ceph monitor daemons. These have fixed IP addresses, so they are often referenced by IP rather than hostname for convenience, or to avoid relying on DNS. Using IPv4 addresses as the host name works already, but IPv6 addresses require rbd-specific escaping because the colon is used as an option separator in the string passed to qemu. Escape these colons, and enclose the IPv6 address in square brackets if a port is specified. Signed-off-by: Josh Durgin <josh.durgin@inktank.com> --- docs/schemas/domaincommon.rng | 5 ++- src/qemu/qemu_command.c | 34 +++++++++++++++---- tests/qemuargv2xmltest.c | 1 + .../qemuxml2argv-disk-drive-network-rbd-ipv6.args | 9 +++++ .../qemuxml2argv-disk-drive-network-rbd-ipv6.xml | 36 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 2 + 6 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 7f3320e..273e54c 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1099,7 +1099,10 @@ </attribute> </optional> <attribute name="name"> - <ref name="dnsName"/> + <choice> + <ref name="dnsName"/> + <ref name="ipAddr"/> + </choice> </attribute> <attribute name="port"> <ref name="unsignedInt"/> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 02fe015..dfc042b 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -34,6 +34,7 @@ #include "virerror.h" #include "virutil.h" #include "virfile.h" +#include "virstring.h" #include "viruuid.h" #include "c-ctype.h" #include "domain_nwfilter.h" @@ -1937,13 +1938,16 @@ qemuBuildRBDString(virConnectPtr conn, if (i) { virBufferAddLit(opt, "\\;"); } - if (disk->hosts[i].port) { - virBufferAsprintf(opt, "%s\\:%s", - disk->hosts[i].name, - disk->hosts[i].port); + + /* assume host containing : is ipv6 */ + if (strchr(disk->hosts[i].name, ':')) { + virBufferEscape(opt, '\\', ":", "[%s]", disk->hosts[i].name); } else { virBufferAsprintf(opt, "%s", disk->hosts[i].name); } + if (disk->hosts[i].port) { + virBufferAsprintf(opt, "\\:%s", disk->hosts[i].port); + } } } @@ -1961,15 +1965,26 @@ error: static int qemuAddRBDHost(virDomainDiskDefPtr disk, char *hostport) { char *port; + size_t skip; + char **parts; disk->nhosts++; if (VIR_REALLOC_N(disk->hosts, disk->nhosts) < 0) goto no_memory; - port = strstr(hostport, "\\:"); + if (strchr(hostport, ']')) { + /* ipv6, strip brackets */ + hostport += 1; + port = strstr(hostport, "]\\:"); + skip = 3; + } else { + port = strstr(hostport, "\\:"); + skip = 2; + } + if (port) { *port = '\0'; - port += 2; + port += skip; disk->hosts[disk->nhosts-1].port = strdup(port); if (!disk->hosts[disk->nhosts-1].port) goto no_memory; @@ -1978,7 +1993,12 @@ static int qemuAddRBDHost(virDomainDiskDefPtr disk, char *hostport) if (!disk->hosts[disk->nhosts-1].port) goto no_memory; } - disk->hosts[disk->nhosts-1].name = strdup(hostport); + + parts = virStringSplit(hostport, "\\:", 0); + if (!parts) + goto no_memory; + disk->hosts[disk->nhosts-1].name = virStringJoin((const char **)parts, ":"); + virStringFreeList(parts); if (!disk->hosts[disk->nhosts-1].name) goto no_memory; diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c index 2923324..e465f3d 100644 --- a/tests/qemuargv2xmltest.c +++ b/tests/qemuargv2xmltest.c @@ -185,6 +185,7 @@ mymain(void) DO_TEST("disk-drive-network-nbd"); DO_TEST("disk-drive-network-gluster"); DO_TEST("disk-drive-network-rbd"); + DO_TEST("disk-drive-network-rbd-ipv6"); /* older format using CEPH_ARGS env var */ DO_TEST("disk-drive-network-rbd-ceph-env"); DO_TEST("disk-drive-network-sheepdog"); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args new file mode 100644 index 0000000..0c67229 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args @@ -0,0 +1,9 @@ +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=rbd:pool/image:auth_supported=none:\ +mon_host=[\:\:1]\:6321\;example.org\:6789\;\ +[ffff\:1234\:567\:abc\:\:0f]\:6322\;\ +[2001\:db8\:\:ff00\:42\:8329]\:6322,\ +if=virtio,format=raw' -net none -serial none -parallel none diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml new file mode 100644 index 0000000..a2ca2d2 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml @@ -0,0 +1,36 @@ +<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='rbd' name='pool/image'> + <host name='::1' port='6321'/> + <host name='example.org' port='6789'/> + <host name='ffff:1234:567:abc::0f' port='6322'/> + <host name='2001:db8::ff00:42:8329' port='6322'/> + </source> + <target dev='vda' bus='virtio'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 31ed116..88e1c36 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -478,6 +478,8 @@ mymain(void) QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT); DO_TEST("disk-drive-network-rbd-auth", QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT); + DO_TEST("disk-drive-network-rbd-ipv6", + QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT); DO_TEST("disk-drive-no-boot", QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_BOOTINDEX); DO_TEST("disk-usb", NONE); -- 1.7.2.5

On 2013年01月24日 10:15, Josh Durgin wrote:
Hosts for rbd are ceph monitor daemons. These have fixed IP addresses, so they are often referenced by IP rather than hostname for convenience, or to avoid relying on DNS. Using IPv4 addresses as the host name works already, but IPv6 addresses require rbd-specific escaping because the colon is used as an option separator in the string passed to qemu.
Escape these colons, and enclose the IPv6 address in square brackets if a port is specified.
Actually the IPv6 address is always enclosed in the code.
Signed-off-by: Josh Durgin<josh.durgin@inktank.com> --- docs/schemas/domaincommon.rng | 5 ++- src/qemu/qemu_command.c | 34 +++++++++++++++---- tests/qemuargv2xmltest.c | 1 + .../qemuxml2argv-disk-drive-network-rbd-ipv6.args | 9 +++++ .../qemuxml2argv-disk-drive-network-rbd-ipv6.xml | 36 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 2 + 6 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 7f3320e..273e54c 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1099,7 +1099,10 @@ </attribute> </optional> <attribute name="name"> -<ref name="dnsName"/> +<choice> +<ref name="dnsName"/> +<ref name="ipAddr"/> +</choice> </attribute> <attribute name="port"> <ref name="unsignedInt"/> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 02fe015..dfc042b 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -34,6 +34,7 @@ #include "virerror.h" #include "virutil.h" #include "virfile.h" +#include "virstring.h" #include "viruuid.h" #include "c-ctype.h" #include "domain_nwfilter.h" @@ -1937,13 +1938,16 @@ qemuBuildRBDString(virConnectPtr conn, if (i) { virBufferAddLit(opt, "\\;"); } - if (disk->hosts[i].port) { - virBufferAsprintf(opt, "%s\\:%s", - disk->hosts[i].name, - disk->hosts[i].port); + + /* assume host containing : is ipv6 */ + if (strchr(disk->hosts[i].name, ':')) { + virBufferEscape(opt, '\\', ":", "[%s]", disk->hosts[i].name); } else { virBufferAsprintf(opt, "%s", disk->hosts[i].name); } + if (disk->hosts[i].port) { + virBufferAsprintf(opt, "\\:%s", disk->hosts[i].port); + } } }
@@ -1961,15 +1965,26 @@ error: static int qemuAddRBDHost(virDomainDiskDefPtr disk, char *hostport) { char *port; + size_t skip; + char **parts;
disk->nhosts++; if (VIR_REALLOC_N(disk->hosts, disk->nhosts)< 0) goto no_memory;
- port = strstr(hostport, "\\:"); + if (strchr(hostport, ']')) { + /* ipv6, strip brackets */ + hostport += 1; + port = strstr(hostport, "]\\:");
This can be simplified as (no need to get the same address twice): if ((port = strchr(hostport, ']'))) { hostport += 1; skip = 3; } else { ... } Others looks pretty neat. ACK.

Hosts for rbd are ceph monitor daemons. These have fixed IP addresses, so they are often referenced by IP rather than hostname for convenience, or to avoid relying on DNS. Using IPv4 addresses as the host name works already, but IPv6 addresses require rbd-specific escaping because the colon is used as an option separator in the string passed to qemu. Escape these colons, and enclose the IPv6 address in square brackets so it is distinguished from the port, which is currently mandatory. Acked-by: Osier Yang <jyang@redhat.com> Signed-off-by: Josh Durgin <josh.durgin@inktank.com> --- Since v1, in response to Osier's review: - corrected commit message - eliminated extra call to strstr() in qemuAddRBDHost docs/schemas/domaincommon.rng | 5 ++- src/qemu/qemu_command.c | 33 ++++++++++++++---- tests/qemuargv2xmltest.c | 1 + .../qemuxml2argv-disk-drive-network-rbd-ipv6.args | 9 +++++ .../qemuxml2argv-disk-drive-network-rbd-ipv6.xml | 36 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 2 + 6 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 7f3320e..273e54c 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1099,7 +1099,10 @@ </attribute> </optional> <attribute name="name"> - <ref name="dnsName"/> + <choice> + <ref name="dnsName"/> + <ref name="ipAddr"/> + </choice> </attribute> <attribute name="port"> <ref name="unsignedInt"/> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 02fe015..f6273c1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -34,6 +34,7 @@ #include "virerror.h" #include "virutil.h" #include "virfile.h" +#include "virstring.h" #include "viruuid.h" #include "c-ctype.h" #include "domain_nwfilter.h" @@ -1937,13 +1938,16 @@ qemuBuildRBDString(virConnectPtr conn, if (i) { virBufferAddLit(opt, "\\;"); } - if (disk->hosts[i].port) { - virBufferAsprintf(opt, "%s\\:%s", - disk->hosts[i].name, - disk->hosts[i].port); + + /* assume host containing : is ipv6 */ + if (strchr(disk->hosts[i].name, ':')) { + virBufferEscape(opt, '\\', ":", "[%s]", disk->hosts[i].name); } else { virBufferAsprintf(opt, "%s", disk->hosts[i].name); } + if (disk->hosts[i].port) { + virBufferAsprintf(opt, "\\:%s", disk->hosts[i].port); + } } } @@ -1961,15 +1965,25 @@ error: static int qemuAddRBDHost(virDomainDiskDefPtr disk, char *hostport) { char *port; + size_t skip; + char **parts; disk->nhosts++; if (VIR_REALLOC_N(disk->hosts, disk->nhosts) < 0) goto no_memory; - port = strstr(hostport, "\\:"); + if ((port = strchr(hostport, ']'))) { + /* ipv6, strip brackets */ + hostport += 1; + skip = 3; + } else { + port = strstr(hostport, "\\:"); + skip = 2; + } + if (port) { *port = '\0'; - port += 2; + port += skip; disk->hosts[disk->nhosts-1].port = strdup(port); if (!disk->hosts[disk->nhosts-1].port) goto no_memory; @@ -1978,7 +1992,12 @@ static int qemuAddRBDHost(virDomainDiskDefPtr disk, char *hostport) if (!disk->hosts[disk->nhosts-1].port) goto no_memory; } - disk->hosts[disk->nhosts-1].name = strdup(hostport); + + parts = virStringSplit(hostport, "\\:", 0); + if (!parts) + goto no_memory; + disk->hosts[disk->nhosts-1].name = virStringJoin((const char **)parts, ":"); + virStringFreeList(parts); if (!disk->hosts[disk->nhosts-1].name) goto no_memory; diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c index 2923324..e465f3d 100644 --- a/tests/qemuargv2xmltest.c +++ b/tests/qemuargv2xmltest.c @@ -185,6 +185,7 @@ mymain(void) DO_TEST("disk-drive-network-nbd"); DO_TEST("disk-drive-network-gluster"); DO_TEST("disk-drive-network-rbd"); + DO_TEST("disk-drive-network-rbd-ipv6"); /* older format using CEPH_ARGS env var */ DO_TEST("disk-drive-network-rbd-ceph-env"); DO_TEST("disk-drive-network-sheepdog"); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args new file mode 100644 index 0000000..0c67229 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args @@ -0,0 +1,9 @@ +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=rbd:pool/image:auth_supported=none:\ +mon_host=[\:\:1]\:6321\;example.org\:6789\;\ +[ffff\:1234\:567\:abc\:\:0f]\:6322\;\ +[2001\:db8\:\:ff00\:42\:8329]\:6322,\ +if=virtio,format=raw' -net none -serial none -parallel none diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml new file mode 100644 index 0000000..a2ca2d2 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml @@ -0,0 +1,36 @@ +<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='rbd' name='pool/image'> + <host name='::1' port='6321'/> + <host name='example.org' port='6789'/> + <host name='ffff:1234:567:abc::0f' port='6322'/> + <host name='2001:db8::ff00:42:8329' port='6322'/> + </source> + <target dev='vda' bus='virtio'/> + </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <memballoon model='virtio'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 31ed116..88e1c36 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -478,6 +478,8 @@ mymain(void) QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT); DO_TEST("disk-drive-network-rbd-auth", QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT); + DO_TEST("disk-drive-network-rbd-ipv6", + QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT); DO_TEST("disk-drive-no-boot", QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_BOOTINDEX); DO_TEST("disk-usb", NONE); -- 1.7.2.5

On 2013年01月25日 10:45, Josh Durgin wrote:
Hosts for rbd are ceph monitor daemons. These have fixed IP addresses, so they are often referenced by IP rather than hostname for convenience, or to avoid relying on DNS. Using IPv4 addresses as the host name works already, but IPv6 addresses require rbd-specific escaping because the colon is used as an option separator in the string passed to qemu.
Escape these colons, and enclose the IPv6 address in square brackets so it is distinguished from the port, which is currently mandatory.
Acked-by: Osier Yang<jyang@redhat.com> Signed-off-by: Josh Durgin<josh.durgin@inktank.com> ---
Since v1, in response to Osier's review: - corrected commit message - eliminated extra call to strstr() in qemuAddRBDHost
docs/schemas/domaincommon.rng | 5 ++- src/qemu/qemu_command.c | 33 ++++++++++++++---- tests/qemuargv2xmltest.c | 1 + .../qemuxml2argv-disk-drive-network-rbd-ipv6.args | 9 +++++ .../qemuxml2argv-disk-drive-network-rbd-ipv6.xml | 36 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 2 + 6 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 7f3320e..273e54c 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1099,7 +1099,10 @@ </attribute> </optional> <attribute name="name"> -<ref name="dnsName"/> +<choice> +<ref name="dnsName"/> +<ref name="ipAddr"/> +</choice> </attribute> <attribute name="port"> <ref name="unsignedInt"/> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 02fe015..f6273c1 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -34,6 +34,7 @@ #include "virerror.h" #include "virutil.h" #include "virfile.h" +#include "virstring.h" #include "viruuid.h" #include "c-ctype.h" #include "domain_nwfilter.h" @@ -1937,13 +1938,16 @@ qemuBuildRBDString(virConnectPtr conn, if (i) { virBufferAddLit(opt, "\\;"); } - if (disk->hosts[i].port) { - virBufferAsprintf(opt, "%s\\:%s", - disk->hosts[i].name, - disk->hosts[i].port); + + /* assume host containing : is ipv6 */ + if (strchr(disk->hosts[i].name, ':')) { + virBufferEscape(opt, '\\', ":", "[%s]", disk->hosts[i].name); } else { virBufferAsprintf(opt, "%s", disk->hosts[i].name); } + if (disk->hosts[i].port) { + virBufferAsprintf(opt, "\\:%s", disk->hosts[i].port); + } } }
@@ -1961,15 +1965,25 @@ error: static int qemuAddRBDHost(virDomainDiskDefPtr disk, char *hostport) { char *port; + size_t skip; + char **parts;
disk->nhosts++; if (VIR_REALLOC_N(disk->hosts, disk->nhosts)< 0) goto no_memory;
- port = strstr(hostport, "\\:"); + if ((port = strchr(hostport, ']'))) { + /* ipv6, strip brackets */ + hostport += 1; + skip = 3; + } else { + port = strstr(hostport, "\\:"); + skip = 2; + } + if (port) { *port = '\0'; - port += 2; + port += skip; disk->hosts[disk->nhosts-1].port = strdup(port); if (!disk->hosts[disk->nhosts-1].port) goto no_memory; @@ -1978,7 +1992,12 @@ static int qemuAddRBDHost(virDomainDiskDefPtr disk, char *hostport) if (!disk->hosts[disk->nhosts-1].port) goto no_memory; } - disk->hosts[disk->nhosts-1].name = strdup(hostport); + + parts = virStringSplit(hostport, "\\:", 0); + if (!parts) + goto no_memory; + disk->hosts[disk->nhosts-1].name = virStringJoin((const char **)parts, ":"); + virStringFreeList(parts); if (!disk->hosts[disk->nhosts-1].name) goto no_memory;
diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c index 2923324..e465f3d 100644 --- a/tests/qemuargv2xmltest.c +++ b/tests/qemuargv2xmltest.c @@ -185,6 +185,7 @@ mymain(void) DO_TEST("disk-drive-network-nbd"); DO_TEST("disk-drive-network-gluster"); DO_TEST("disk-drive-network-rbd"); + DO_TEST("disk-drive-network-rbd-ipv6"); /* older format using CEPH_ARGS env var */ DO_TEST("disk-drive-network-rbd-ceph-env"); DO_TEST("disk-drive-network-sheepdog"); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args new file mode 100644 index 0000000..0c67229 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args @@ -0,0 +1,9 @@ +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=rbd:pool/image:auth_supported=none:\ +mon_host=[\:\:1]\:6321\;example.org\:6789\;\ +[ffff\:1234\:567\:abc\:\:0f]\:6322\;\ +[2001\:db8\:\:ff00\:42\:8329]\:6322,\ +if=virtio,format=raw' -net none -serial none -parallel none diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml new file mode 100644 index 0000000..a2ca2d2 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml @@ -0,0 +1,36 @@ +<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='rbd' name='pool/image'> +<host name='::1' port='6321'/> +<host name='example.org' port='6789'/> +<host name='ffff:1234:567:abc::0f' port='6322'/> +<host name='2001:db8::ff00:42:8329' port='6322'/> +</source> +<target dev='vda' bus='virtio'/> +</disk> +<controller type='usb' index='0'/> +<controller type='ide' index='0'/> +<memballoon model='virtio'/> +</devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 31ed116..88e1c36 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -478,6 +478,8 @@ mymain(void) QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT); DO_TEST("disk-drive-network-rbd-auth", QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT); + DO_TEST("disk-drive-network-rbd-ipv6", + QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT); DO_TEST("disk-drive-no-boot", QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_BOOTINDEX); DO_TEST("disk-usb", NONE);
Though now it's already in freezing. But I guess you will want the feature as soon as posible, and I don't think it could cause any problem for the build, so pushed. Osier

On 01/23/2013 08:20 PM, Osier Yang wrote:
On 2013年01月24日 10:15, Josh Durgin wrote:
Hosts for rbd are ceph monitor daemons. These have fixed IP addresses, so they are often referenced by IP rather than hostname for convenience, or to avoid relying on DNS. Using IPv4 addresses as the host name works already, but IPv6 addresses require rbd-specific escaping because the colon is used as an option separator in the string passed to qemu.
Escape these colons, and enclose the IPv6 address in square brackets if a port is specified.
Actually the IPv6 address is always enclosed in the code.
Indeed.
Signed-off-by: Josh Durgin<josh.durgin@inktank.com> --- docs/schemas/domaincommon.rng | 5 ++- src/qemu/qemu_command.c | 34 +++++++++++++++---- tests/qemuargv2xmltest.c | 1 + .../qemuxml2argv-disk-drive-network-rbd-ipv6.args | 9 +++++ .../qemuxml2argv-disk-drive-network-rbd-ipv6.xml | 36 ++++++++++++++++++++ tests/qemuxml2argvtest.c | 2 + 6 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd-ipv6.xml
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 7f3320e..273e54c 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1099,7 +1099,10 @@ </attribute> </optional> <attribute name="name"> -<ref name="dnsName"/> +<choice> +<ref name="dnsName"/> +<ref name="ipAddr"/> +</choice> </attribute> <attribute name="port"> <ref name="unsignedInt"/> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 02fe015..dfc042b 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -34,6 +34,7 @@ #include "virerror.h" #include "virutil.h" #include "virfile.h" +#include "virstring.h" #include "viruuid.h" #include "c-ctype.h" #include "domain_nwfilter.h" @@ -1937,13 +1938,16 @@ qemuBuildRBDString(virConnectPtr conn, if (i) { virBufferAddLit(opt, "\\;"); } - if (disk->hosts[i].port) { - virBufferAsprintf(opt, "%s\\:%s", - disk->hosts[i].name, - disk->hosts[i].port); + + /* assume host containing : is ipv6 */ + if (strchr(disk->hosts[i].name, ':')) { + virBufferEscape(opt, '\\', ":", "[%s]", disk->hosts[i].name); } else { virBufferAsprintf(opt, "%s", disk->hosts[i].name); } + if (disk->hosts[i].port) { + virBufferAsprintf(opt, "\\:%s", disk->hosts[i].port); + } } }
@@ -1961,15 +1965,26 @@ error: static int qemuAddRBDHost(virDomainDiskDefPtr disk, char *hostport) { char *port; + size_t skip; + char **parts;
disk->nhosts++; if (VIR_REALLOC_N(disk->hosts, disk->nhosts)< 0) goto no_memory;
- port = strstr(hostport, "\\:"); + if (strchr(hostport, ']')) { + /* ipv6, strip brackets */10000 / 384 = + hostport += 1; + port = strstr(hostport, "]\\:");
This can be simplified as (no need to get the same address twice):
if ((port = strchr(hostport, ']'))) { hostport += 1; skip = 3; } else { ... }
Others looks pretty neat. ACK.
Good point, I'd forgotten that the port is mandatory when a name is specified. Sending a v2. Thanks! Josh
participants (2)
-
Josh Durgin
-
Osier Yang