</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, ":")) {