Signed-off-by: Harsh Prateek Bora <harsh@xxxxxxxxxxxxxxxxxx>
---
docs/schemas/domaincommon.rng | 8 ++
src/conf/domain_conf.c | 28 +++++-
src/conf/domain_conf.h | 11 +++
src/libvirt_private.syms | 2 +
src/qemu/qemu_command.c | 204 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 251 insertions(+), 2 deletions(-)
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index f47fdad..89d9b9f 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -1048,6 +1048,7 @@
<value>nbd</value>
<value>rbd</value>
<value>sheepdog</value>
+ <value>gluster</value>
</choice>
</attribute>
<optional>
@@ -1061,6 +1062,13 @@
<attribute name="port">
<ref name="unsignedInt"/>
</attribute>
+ <attribute name="transport">
+ <choice>
+ <value>tcp</value>
+ <value>unix</value>
+ <value>rdma</value>
+ </choice>
+ </attribute>
</element>
</zeroOrMore>
<empty/>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 33e1e7f..838f079 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -214,7 +214,13 @@ VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST,
VIR_ENUM_IMPL(virDomainDiskProtocol, VIR_DOMAIN_DISK_PROTOCOL_LAST,
"nbd",
"rbd",
- "sheepdog")
+ "sheepdog",
+ "gluster")
+
+VIR_ENUM_IMPL(virDomainDiskProtocolTransport, VIR_DOMAIN_DISK_PROTO_TRANS_LAST,
+ "tcp",
+ "unix",
+ "rdma")
VIR_ENUM_IMPL(virDomainDiskSecretType, VIR_DOMAIN_DISK_SECRET_TYPE_LAST,
"none",
@@ -3460,6 +3466,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
char *source = NULL;
char *target = NULL;
char *protocol = NULL;
+ char *protocol_transport;
char *trans = NULL;
virDomainDiskHostDefPtr hosts = NULL;
int nhosts = 0;
@@ -3566,6 +3573,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
}
hosts[nhosts].name = NULL;
hosts[nhosts].port = NULL;
+ hosts[nhosts].transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
nhosts++;
hosts[nhosts - 1].name = virXMLPropString(child, "name");
@@ -3580,6 +3588,17 @@ virDomainDiskDefParseXML(virCapsPtr caps,
"%s", _("missing port for host"));
goto error;
}
+ /* transport can be tcp (default), unix or rdma. */
+ protocol_transport = virXMLPropString(child, "transport");
+ if (protocol_transport != NULL) {
+ hosts[nhosts - 1].transport = virDomainDiskProtocolTransportTypeFromString(protocol_transport);
+ if (hosts[nhosts - 1].transport < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown protocol transport type '%s'"),
+ protocol_transport);
+ goto error;
+ }
+ }
}
child = child->next;
}
@@ -11756,8 +11775,13 @@ virDomainDiskDefFormat(virBufferPtr buf,
for (i = 0; i < def->nhosts; i++) {
virBufferEscapeString(buf, " <host name='%s'",
def->hosts[i].name);
- virBufferEscapeString(buf, " port='%s'/>\n",
+ virBufferEscapeString(buf, " port='%s'",
def->hosts[i].port);
+ if (def->hosts[i].transport) {
+ virBufferAsprintf(buf, " transport='%s'",
+ virDomainDiskProtocolTransportTypeToString(def->hosts[i].transport));
+ }
+ virBufferAddLit(buf, "/>\n");
}
virBufferAddLit(buf, " </source>\n");
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 14dead3..7ba7e9b 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -456,10 +456,19 @@ enum virDomainDiskProtocol {
VIR_DOMAIN_DISK_PROTOCOL_NBD,
VIR_DOMAIN_DISK_PROTOCOL_RBD,
VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG,
+ VIR_DOMAIN_DISK_PROTOCOL_GLUSTER,
VIR_DOMAIN_DISK_PROTOCOL_LAST
};
+enum virDomainDiskProtocolTransport {
+ VIR_DOMAIN_DISK_PROTO_TRANS_TCP,
+ VIR_DOMAIN_DISK_PROTO_TRANS_UNIX,
+ VIR_DOMAIN_DISK_PROTO_TRANS_RDMA,
+
+ VIR_DOMAIN_DISK_PROTO_TRANS_LAST
+};
+
enum virDomainDiskTray {
VIR_DOMAIN_DISK_TRAY_CLOSED,
VIR_DOMAIN_DISK_TRAY_OPEN,
@@ -481,6 +490,7 @@ typedef virDomainDiskHostDef *virDomainDiskHostDefPtr;
struct _virDomainDiskHostDef {
char *name;
char *port;
+ int transport; /* enum virDomainDiskProtocolTransport */
};
enum virDomainDiskIo {
@@ -2166,6 +2176,7 @@ VIR_ENUM_DECL(virDomainDiskBus)
VIR_ENUM_DECL(virDomainDiskCache)
VIR_ENUM_DECL(virDomainDiskErrorPolicy)
VIR_ENUM_DECL(virDomainDiskProtocol)
+VIR_ENUM_DECL(virDomainDiskProtocolTransport)
VIR_ENUM_DECL(virDomainDiskIo)
VIR_ENUM_DECL(virDomainDiskSecretType)
VIR_ENUM_DECL(virDomainDiskTray)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index dab607a..8e70837 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -350,6 +350,8 @@ virDomainDiskInsertPreAlloced;
virDomainDiskIoTypeFromString;
virDomainDiskIoTypeToString;
virDomainDiskPathByName;
+virDomainDiskProtocolTransportTypeFromString;
+virDomainDiskProtocolTransportTypeToString;
virDomainDiskRemove;
virDomainDiskRemoveByName;
virDomainDiskTypeFromString;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 20730a9..0bed2bc 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -2021,6 +2021,168 @@ no_memory:
return -1;
}
+static int qemuParseGlusterString(virDomainDiskDefPtr def)
+{
+ char *host = NULL, *port = NULL, *volimg, *transp = NULL, *marker;
+
+ if (STRPREFIX(def->src, "+")) {
+ transp = def->src;
+ transp++;
+ marker = strstr(def->src, "://");
+ *marker++ = '\0';
+ marker += 2;
+ } else {
+ /* transport type not specified, use tcp as default */
+ def->hosts->transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
+ marker = strstr(def->src, "://");
+ marker += 3;
+ }
+
+ if (transp) {
+ def->hosts->transport = virDomainDiskProtocolTransportTypeFromString(transp);
+ if (def->hosts->transport < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Invalid gluster transport type '%s'"), transp);
+ return -1;
+ }
+ }
+
+ /* now marker points to string which can start with one of the following:
+ * IPv6 address in square brackets followed by port (optional)
+ * <hostname> or <IPv4 address> followed by port (optional)
+ * '/' if its a unix socket followed by path to gluster disk volume/image
+ */
+
+ /* parse server, port */
+ if (def->hosts->transport != VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) {
+ if (STRPREFIX(marker, "[")) {
+ /* IPv6 addr */
+ host = ++marker;
+ marker = strchr(host, ']');
+ if (!marker) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse IPv6 addr for gluster host %s "), host);
+ return -1;
+ }
+ *marker++ = '\0';
+ /* parse port if specified */
+ if (STRPREFIX(marker, ":")) {
+ port = ++marker;
+ marker = strchr(port, '/');
+ if (!marker) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse filename for gluster disk %s "), port);
+ return -1;
+ }
+ *marker++ = '\0';
+ } else {
+ marker++; /* port not specified, skip slash */
+ }
+ } else {
+ /* IPv4 address / hostname followed by port (optional) */
+ host = marker;
+ marker = strchr(host, '/'); /* skip to path to gluster disk vol/img */
+ if (!marker) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot parse filename for gluster disk %s "), port);
+ return -1;
+ }
+ *marker++ = '\0';
+ port = strchr(host, ':');
+ if (port) {
+ /* port was specified with host, separate both */
+ *port++ = '\0';
+ }
+ }
+
+ /* host points to hostname / IPv4 / IPv6 addr
+ * port points to port or NULL is port was not specified
+ */
+ } else {
+ /* transport type is unix, expect one more slash
+ * followed by path to gluster disk vol/img */
+ if (STRPREFIX(marker, "/")) {
+ marker++;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Gluster unix transport url starts with 3 slashes i.e. gluster+unix:///"));
+ return -1;
+ }
+ }
+
+ /* marker now points to path to gluster disk vol/img */
+ volimg = marker;
+
+ /* if transport type = unix, path to gluster disk vol/img
+ * is followed by ?socket=<path/to/socket> */
+ if (def->hosts->transport == VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) {
+ if (strstr(marker, "?socket=")) {
+ /* In libvirt xml, socket path is to be provided as
+ * <host name='/path/to/socket' port='0'>
+ */
+ host = strchr(marker, '=');
+ *host++ = '\0';
+ }
+ }
+
+ if (VIR_ALLOC(def->hosts) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ def->nhosts = 1;
+ def->hosts->name = host;
+ if (port) {
+ def->hosts->port = port;
+ } else {
+ def->hosts->port = strdup("0");
+ }
+ if (!def->hosts->port) {
+ virReportOOMError();
+ return -1;
+ }
+ def->src = strdup(volimg);
+ if (!def->src) {
+ virReportOOMError();
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+qemuBuildGlusterString(virDomainDiskDefPtr disk, virBufferPtr opt)
+{
+ int ret = 0;
+ virBufferAddLit(opt, "file=");
+ if (disk->nhosts != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("gluster accepts only one host"));
+ ret = -1;
+ } else {
+ virBufferAsprintf(opt, "gluster+%s://",
+ virDomainDiskProtocolTransportTypeToString(disk->hosts->transport));
+
+ /* if transport type is not unix, specify server:port */
+ if (disk->hosts->transport != VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) {
+ if (strstr(disk->hosts->name, ":")) {
+ /* if IPv6 addr, use square brackets to enclose it */
+ virBufferAsprintf(opt, "[%s]:%s", disk->hosts->name, disk->hosts->port);
+ } else {
+ virBufferAsprintf(opt, "%s:%s", disk->hosts->name, disk->hosts->port);
+ }
+ }
+
+ /* append source path to gluster disk image */
+ virBufferAsprintf(opt, "/%s", disk->src);
+
+ /* if transport type is unix, server name is path to unix socket, ignore port */
+ if (disk->hosts->transport == VIR_DOMAIN_DISK_PROTO_TRANS_UNIX) {
+ virBufferAsprintf(opt, "?socket=%s", disk->hosts->name);
+ }
+ }
+ return ret;
+}
+
char *
qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainDiskDefPtr disk,
@@ -2162,6 +2324,12 @@ qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED,
goto error;
virBufferAddChar(&opt, ',');
break;
+ case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
+ if (qemuBuildGlusterString(disk, &opt) < 0)
+ goto error;
+ virBufferAddChar(&opt, ',');
+ break;
+
case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
if (disk->nhosts == 0) {
virBufferEscape(&opt, ',', ",", "file=sheepdog:%s,",
@@ -5242,6 +5410,18 @@ qemuBuildCommandLine(virConnectPtr conn,
file = virBufferContentAndReset(&opt);
}
break;
+ case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
+ {
+ virBuffer opt = VIR_BUFFER_INITIALIZER;
+ if (qemuBuildGlusterString(disk, &opt) < 0)
+ goto error;
+ if (virBufferError(&opt)) {
+ virReportOOMError();
+ goto error;
+ }
+ file = virBufferContentAndReset(&opt);
+ }
+ break;
case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
if (disk->nhosts == 0) {
if (virAsprintf(&file, "sheepdog:%s,", disk->src) < 0) {
@@ -6937,6 +7117,21 @@ qemuParseCommandLineDisk(virCapsPtr caps,
goto cleanup;
VIR_FREE(p);
+ } else if (STRPREFIX(def->src, "gluster")) {
+ char *p = def->src;
+
+ def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+ def->protocol = VIR_DOMAIN_DISK_PROTOCOL_GLUSTER;
+ def->src = strdup(p + strlen("gluster"));
+ if (!def->src) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (qemuParseGlusterString(def) < 0)
+ goto cleanup;
+
+ VIR_FREE(p);
} else if (STRPREFIX(def->src, "sheepdog:")) {
char *p = def->src;
char *port, *vdi;
@@ -8126,6 +8321,10 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_RBD;
val += strlen("rbd:");
+ } else if (STRPREFIX(val, "gluster")) {
+ disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+ disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_GLUSTER;
+ val += strlen("gluster");
} else if (STRPREFIX(val, "sheepdog:")) {
disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG;
@@ -8211,6 +8410,11 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
goto no_memory;
}
break;
+ case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
+ if (qemuParseGlusterString(disk) < 0)
+ goto error;
+
+ break;
}
}