[libvirt] [PATCH v2] Implement DNS SRV record into the bridge driver
by Michal Novotny
Hi,
this is the second version of my patch to the bridge driver and
libvirt XML file to include support for the SRV records in the DNS.
The syntax is based on DNSMasq man page and tests for both xml2xml
and xml2argv were added as well.
Differences between v1 and v2:
- A minor rewrite of integer parsing functionality
- Extend tests to test with both minimal and full set of attributes
- Check for service name length implemented
Signed-off-by: Michal Novotny <minovotn(a)redhat.com>
---
docs/formatnetwork.html.in | 12 ++
docs/schemas/network.rng | 26 ++++
src/conf/network_conf.c | 130 +++++++++++++++++++-
src/conf/network_conf.h | 16 +++
src/network/bridge_driver.c | 43 +++++++
.../nat-network-dns-srv-record-minimal.argv | 1 +
.../nat-network-dns-srv-record-minimal.xml | 26 ++++
.../nat-network-dns-srv-record.argv | 1 +
.../nat-network-dns-srv-record.xml | 26 ++++
tests/networkxml2argvtest.c | 2 +
.../nat-network-dns-srv-record-minimal.xml | 26 ++++
.../nat-network-dns-srv-record.xml | 26 ++++
.../nat-network-dns-srv-record-minimal.xml | 26 ++++
.../nat-network-dns-srv-record.xml | 26 ++++
tests/networkxml2xmltest.c | 2 +
16 files changed, 391 insertions(+), 2 deletions(-)
create mode 100644 tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv
create mode 100644 tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.xml
create mode 100644 tests/networkxml2argvdata/nat-network-dns-srv-record.argv
create mode 100644 tests/networkxml2argvdata/nat-network-dns-srv-record.xml
create mode 100644 tests/networkxml2xmlin/nat-network-dns-srv-record-minimal.xml
create mode 100644 tests/networkxml2xmlin/nat-network-dns-srv-record.xml
create mode 100644 tests/networkxml2xmlout/nat-network-dns-srv-record-minimal.xml
create mode 100644 tests/networkxml2xmlout/nat-network-dns-srv-record.xml
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 99031d0..51b1581 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -342,6 +342,7 @@
<mac address='00:16:3E:5D:C7:9E'/>
<dns>
<txt name="example" value="example value" />
+ <srv service="name" protocol="tcp" domain="test-domain-name" target="." port="1024" priority="10" weight="10"/>
</dns>
<ip address="192.168.122.1" netmask="255.255.255.0">
<dhcp>
@@ -390,6 +391,17 @@
<span class="since">Since 0.9.3</span>
</dd>
</dl>
+ <dl>
+ <dt><code>srv</code></dt>
+ <dd>The <code>dns</code> element can have also 0 or more <code>srv</code>
+ record elements. Each <code>srv</code> record element defines a DNS SRV record
+ and has 2 mandatory and 5 optional attributes. The mandatory attributes
+ are service name and protocol (tcp, udp) and the optional attributes are
+ target, port, priority, weight and domain as defined in DNS server SRV
+ RFC (RFC 2782).
+ <span class="since">Since 0.9.5</span>
+ </dd>
+ </dl>
</dd>
<dt><code>ip</code></dt>
<dd>The <code>address</code> attribute defines an IPv4 address in
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 1c44471..dae2799 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -138,6 +138,19 @@
</element>
</zeroOrMore>
<zeroOrMore>
+ <element name="srv">
+ <attribute name="service"><text/></attribute>
+ <attribute name="protocol"><ref name="protocol"/></attribute>
+ <optional>
+ <attribute name="domain"><ref name="dnsName"/></attribute>
+ <attribute name="target"><text/></attribute>
+ <attribute name="port"><ref name="unsignedShort"/></attribute>
+ <attribute name="priority"><ref name="unsignedShort"/></attribute>
+ <attribute name="weight"><ref name="unsignedShort"/></attribute>
+ </optional>
+ </element>
+ </zeroOrMore>
+ <zeroOrMore>
<element name="host">
<attribute name="ip"><ref name="ipv4Addr"/></attribute>
<oneOrMore>
@@ -206,6 +219,19 @@
</element>
</define>
+ <define name='unsignedShort'>
+ <data type='integer'>
+ <param name="minInclusive">0</param>
+ <param name="maxInclusive">65535</param>
+ </data>
+ </define>
+
+ <define name='protocol'>
+ <data type='string'>
+ <param name='pattern'>(tcp)|(udp)</param>
+ </data>
+ </define>
+
<define name='addr-family'>
<data type='string'>
<param name="pattern">(ipv4)|(ipv6)</param>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index b11c482..517c4d6 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -137,6 +137,15 @@ static void virNetworkDNSDefFree(virNetworkDNSDefPtr def)
}
VIR_FREE(def->hosts);
}
+ if (def->nsrvrecords) {
+ while (def->nsrvrecords--) {
+ VIR_FREE(def->srvrecords[def->nsrvrecords].domain);
+ VIR_FREE(def->srvrecords[def->nsrvrecords].service);
+ VIR_FREE(def->srvrecords[def->nsrvrecords].protocol);
+ VIR_FREE(def->srvrecords[def->nsrvrecords].target);
+ }
+ VIR_FREE(def->srvrecords);
+ }
VIR_FREE(def);
}
}
@@ -552,8 +561,99 @@ error:
}
static int
+virNetworkDNSSrvDefParseXML(virNetworkDNSDefPtr def,
+ xmlNodePtr cur,
+ xmlXPathContextPtr ctxt)
+{
+ char *domain;
+ char *service;
+ char *protocol;
+ char *target;
+ int port;
+ int priority;
+ int weight;
+ int ret = 0;
+ char xpath[1024] = { 0 };
+
+ if (!(service = virXMLPropString(cur, "service"))) {
+ virNetworkReportError(VIR_ERR_XML_DETAIL,
+ "%s", _("Missing required service attribute in dns srv record"));
+ goto error;
+ }
+
+ if (strlen(service) > DNS_RECORD_LENGTH_SRV) {
+ virNetworkReportError(VIR_ERR_XML_DETAIL,
+ "%s", _("Service name is too long, limit is %d bytes"), DNS_RECORD_LENGTH_SRV);
+ goto error;
+ }
+
+ if (!(protocol = virXMLPropString(cur, "protocol"))) {
+ virNetworkReportError(VIR_ERR_XML_DETAIL,
+ _("Missing required protocol attribute in dns srv record '%s'"), service);
+ goto error;
+ }
+
+ /* Check whether protocol value is the supported one */
+ if (STRNEQ(protocol, "tcp") && (STRNEQ(protocol, "udp"))) {
+ virNetworkReportError(VIR_ERR_XML_DETAIL,
+ _("Invalid protocol attribute value '%s'"), protocol);
+ goto error;
+ }
+
+ if (VIR_REALLOC_N(def->srvrecords, def->nsrvrecords + 1) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+
+ def->srvrecords[def->nsrvrecords].service = service;
+ def->srvrecords[def->nsrvrecords].protocol = protocol;
+ def->srvrecords[def->nsrvrecords].domain = NULL;
+ def->srvrecords[def->nsrvrecords].target = NULL;
+ def->srvrecords[def->nsrvrecords].port = 0;
+ def->srvrecords[def->nsrvrecords].priority = 0;
+ def->srvrecords[def->nsrvrecords].weight = 0;
+
+ /* Following attributes are optional but we had to make sure their NULL above */
+ if ((target = virXMLPropString(cur, "target")) && (domain = virXMLPropString(cur, "domain"))) {
+ snprintf(xpath, sizeof(xpath), "string(//network/dns/srv[@service='%s']/@port)", service);
+ if (virXPathInt(xpath, ctxt, &port))
+ def->srvrecords[def->nsrvrecords].port = port;
+
+ snprintf(xpath, sizeof(xpath), "string(//network/dns/srv[@service='%s']/@priority)", service);
+ if (virXPathInt(xpath, ctxt, &priority))
+ def->srvrecords[def->nsrvrecords].priority = priority;
+
+ snprintf(xpath, sizeof(xpath), "string(//network/dns/srv[@service='%s']/@weight)", service);
+ if (virXPathInt(xpath, ctxt, &weight))
+ def->srvrecords[def->nsrvrecords].weight = weight;
+
+ def->srvrecords[def->nsrvrecords].domain = domain;
+ def->srvrecords[def->nsrvrecords].target = target;
+ def->srvrecords[def->nsrvrecords].port = port;
+ def->srvrecords[def->nsrvrecords].priority = priority;
+ def->srvrecords[def->nsrvrecords].weight = weight;
+ }
+
+ def->nsrvrecords++;
+
+ goto cleanup;
+
+error:
+ VIR_FREE(domain);
+ VIR_FREE(service);
+ VIR_FREE(protocol);
+ VIR_FREE(target);
+
+ ret = 1;
+
+cleanup:
+ return ret;
+}
+
+static int
virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef,
- xmlNodePtr node)
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt)
{
xmlNodePtr cur;
int ret = -1;
@@ -598,6 +698,11 @@ virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef,
name = NULL;
value = NULL;
} else if (cur->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(cur->name, BAD_CAST "srv")) {
+ ret = virNetworkDNSSrvDefParseXML(def, cur, ctxt);
+ if (ret < 0)
+ goto error;
+ } else if (cur->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "host")) {
ret = virNetworkDNSHostsDefParseXML(def, cur);
if (ret < 0)
@@ -888,7 +993,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
dnsNode = virXPathNode("./dns", ctxt);
if (dnsNode != NULL) {
- if (virNetworkDNSDefParseXML(&def->dns, dnsNode) < 0)
+ if (virNetworkDNSDefParseXML(&def->dns, dnsNode, ctxt) < 0)
goto error;
}
@@ -1147,6 +1252,27 @@ virNetworkDNSDefFormat(virBufferPtr buf,
def->txtrecords[i].value);
}
+ for (i = 0 ; i < def->nsrvrecords ; i++) {
+ if (def->srvrecords[i].service && def->srvrecords[i].protocol) {
+ virBufferAsprintf(buf, " <srv service='%s' protocol='%s' ",
+ def->srvrecords[i].service,
+ def->srvrecords[i].protocol);
+
+ if (def->srvrecords[i].domain)
+ virBufferAsprintf(buf, "domain='%s' ", def->srvrecords[i].domain);
+ if (def->srvrecords[i].target)
+ virBufferAsprintf(buf, "target='%s' ", def->srvrecords[i].target);
+ if (def->srvrecords[i].port)
+ virBufferAsprintf(buf, "port='%d' ", def->srvrecords[i].port);
+ if (def->srvrecords[i].priority)
+ virBufferAsprintf(buf, "priority='%d' ", def->srvrecords[i].priority);
+ if (def->srvrecords[i].weight)
+ virBufferAsprintf(buf, "weight='%d' ", def->srvrecords[i].weight);
+
+ virBufferAsprintf(buf, "/>\n");
+ }
+ }
+
if (def->nhosts) {
int ii, j;
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 869085e..5f05a3a 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -24,6 +24,8 @@
#ifndef __NETWORK_CONF_H__
# define __NETWORK_CONF_H__
+#define DNS_RECORD_LENGTH_SRV (512 - 30) /* Limit minus overhead as mentioned in RFC-2782 */
+
# include <libxml/parser.h>
# include <libxml/tree.h>
# include <libxml/xpath.h>
@@ -67,6 +69,18 @@ struct _virNetworkDNSTxtRecordsDef {
char *value;
};
+typedef struct _virNetworkDNSSrvRecordsDef virNetworkDNSSrvRecordsDef;
+typedef virNetworkDNSSrvRecordsDef *virNetworkDNSSrvRecordsDefPtr;
+struct _virNetworkDNSSrvRecordsDef {
+ char *domain;
+ char *service;
+ char *protocol;
+ char *target;
+ int port;
+ int priority;
+ int weight;
+};
+
struct _virNetworkDNSHostsDef {
virSocketAddr ip;
int nnames;
@@ -80,6 +94,8 @@ struct _virNetworkDNSDef {
virNetworkDNSTxtRecordsDefPtr txtrecords;
unsigned int nhosts;
virNetworkDNSHostsDefPtr hosts;
+ unsigned int nsrvrecords;
+ virNetworkDNSSrvRecordsDefPtr srvrecords;
};
typedef struct _virNetworkDNSDef *virNetworkDNSDefPtr;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index c90db63..f4d952f 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -559,6 +559,49 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
virCommandAddArgPair(cmd, "--txt-record", record);
VIR_FREE(record);
}
+
+ for (i = 0; i < dns->nsrvrecords; i++) {
+ char *record = NULL;
+ char *recordPort = NULL;
+ char *recordPriority = NULL;
+ char *recordWeight = NULL;
+
+ if (dns->srvrecords[i].service && dns->srvrecords[i].protocol) {
+ if (dns->srvrecords[i].port) {
+ if (virAsprintf(&recordPort, "%d", dns->srvrecords[i].port) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+ if (dns->srvrecords[i].priority) {
+ if (virAsprintf(&recordPriority, "%d", dns->srvrecords[i].priority) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+ if (dns->srvrecords[i].weight) {
+ if (virAsprintf(&recordWeight, "%d", dns->srvrecords[i].weight) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+
+ if (virAsprintf(&record, "%s.%s.%s,%s,%s,%s,%s",
+ dns->srvrecords[i].service,
+ dns->srvrecords[i].protocol,
+ dns->srvrecords[i].domain ? dns->srvrecords[i].domain : "",
+ dns->srvrecords[i].target ? dns->srvrecords[i].target : "",
+ recordPort ? recordPort : "",
+ recordPriority ? recordPriority : "",
+ recordWeight ? recordWeight : "") < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ virCommandAddArgPair(cmd, "--srv-host", record);
+ VIR_FREE(record);
+ }
+ }
}
/*
diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv
new file mode 100644
index 0000000..174f751
--- /dev/null
+++ b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv
@@ -0,0 +1 @@
+/usr/sbin/dnsmasq --strict-order --bind-interfaces --conf-file= --except-interface lo --srv-host=name.tcp.,,,, --listen-address 192.168.122.1 --listen-address 192.168.123.1 --listen-address 2001:db8:ac10:fe01::1 --listen-address 2001:db8:ac10:fd01::1 --listen-address 10.24.10.1 --dhcp-range 192.168.122.2,192.168.122.254 --dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases --dhcp-lease-max=253 --dhcp-no-override --dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
\ No newline at end of file
diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.xml b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.xml
new file mode 100644
index 0000000..e9b7680
--- /dev/null
+++ b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.xml
@@ -0,0 +1,26 @@
+<network>
+ <name>default</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward dev='eth1' mode='nat'>
+ <interface dev='eth1'/>
+ </forward>
+ <bridge name='virbr0' stp='on' delay='0' />
+ <dns>
+ <srv service='name' protocol='tcp' />
+ </dns>
+ <ip address='192.168.122.1' netmask='255.255.255.0'>
+ <dhcp>
+ <range start='192.168.122.2' end='192.168.122.254' />
+ <host mac='00:16:3e:77:e2:ed' name='a.example.com' ip='192.168.122.10' />
+ <host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11' />
+ </dhcp>
+ </ip>
+ <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
+ </ip>
+ <ip family='ipv4' address='10.24.10.1'>
+ </ip>
+</network>
diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv
new file mode 100644
index 0000000..2ea9809
--- /dev/null
+++ b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv
@@ -0,0 +1 @@
+/usr/sbin/dnsmasq --strict-order --bind-interfaces --conf-file= --except-interface lo --srv-host=name.tcp.test-domain-name,.,1024,10,10 --listen-address 192.168.122.1 --listen-address 192.168.123.1 --listen-address 2001:db8:ac10:fe01::1 --listen-address 2001:db8:ac10:fd01::1 --listen-address 10.24.10.1 --dhcp-range 192.168.122.2,192.168.122.254 --dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases --dhcp-lease-max=253 --dhcp-no-override --dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
\ No newline at end of file
diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record.xml b/tests/networkxml2argvdata/nat-network-dns-srv-record.xml
new file mode 100644
index 0000000..4be85b5
--- /dev/null
+++ b/tests/networkxml2argvdata/nat-network-dns-srv-record.xml
@@ -0,0 +1,26 @@
+<network>
+ <name>default</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward dev='eth1' mode='nat'>
+ <interface dev='eth1'/>
+ </forward>
+ <bridge name='virbr0' stp='on' delay='0' />
+ <dns>
+ <srv service='name' protocol='tcp' domain='test-domain-name' target='.' port='1024' priority='10' weight='10' />
+ </dns>
+ <ip address='192.168.122.1' netmask='255.255.255.0'>
+ <dhcp>
+ <range start='192.168.122.2' end='192.168.122.254' />
+ <host mac='00:16:3e:77:e2:ed' name='a.example.com' ip='192.168.122.10' />
+ <host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11' />
+ </dhcp>
+ </ip>
+ <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
+ </ip>
+ <ip family='ipv4' address='10.24.10.1'>
+ </ip>
+</network>
diff --git a/tests/networkxml2argvtest.c b/tests/networkxml2argvtest.c
index 4a11d6f..2dd9b7f 100644
--- a/tests/networkxml2argvtest.c
+++ b/tests/networkxml2argvtest.c
@@ -120,6 +120,8 @@ mymain(void)
DO_TEST("netboot-network");
DO_TEST("netboot-proxy-network");
DO_TEST("nat-network-dns-txt-record");
+ DO_TEST("nat-network-dns-srv-record");
+ DO_TEST("nat-network-dns-srv-record-minimal");
DO_TEST("nat-network-dns-hosts");
return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
diff --git a/tests/networkxml2xmlin/nat-network-dns-srv-record-minimal.xml b/tests/networkxml2xmlin/nat-network-dns-srv-record-minimal.xml
new file mode 100644
index 0000000..e9b7680
--- /dev/null
+++ b/tests/networkxml2xmlin/nat-network-dns-srv-record-minimal.xml
@@ -0,0 +1,26 @@
+<network>
+ <name>default</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward dev='eth1' mode='nat'>
+ <interface dev='eth1'/>
+ </forward>
+ <bridge name='virbr0' stp='on' delay='0' />
+ <dns>
+ <srv service='name' protocol='tcp' />
+ </dns>
+ <ip address='192.168.122.1' netmask='255.255.255.0'>
+ <dhcp>
+ <range start='192.168.122.2' end='192.168.122.254' />
+ <host mac='00:16:3e:77:e2:ed' name='a.example.com' ip='192.168.122.10' />
+ <host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11' />
+ </dhcp>
+ </ip>
+ <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
+ </ip>
+ <ip family='ipv4' address='10.24.10.1'>
+ </ip>
+</network>
diff --git a/tests/networkxml2xmlin/nat-network-dns-srv-record.xml b/tests/networkxml2xmlin/nat-network-dns-srv-record.xml
new file mode 100644
index 0000000..4be85b5
--- /dev/null
+++ b/tests/networkxml2xmlin/nat-network-dns-srv-record.xml
@@ -0,0 +1,26 @@
+<network>
+ <name>default</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward dev='eth1' mode='nat'>
+ <interface dev='eth1'/>
+ </forward>
+ <bridge name='virbr0' stp='on' delay='0' />
+ <dns>
+ <srv service='name' protocol='tcp' domain='test-domain-name' target='.' port='1024' priority='10' weight='10' />
+ </dns>
+ <ip address='192.168.122.1' netmask='255.255.255.0'>
+ <dhcp>
+ <range start='192.168.122.2' end='192.168.122.254' />
+ <host mac='00:16:3e:77:e2:ed' name='a.example.com' ip='192.168.122.10' />
+ <host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11' />
+ </dhcp>
+ </ip>
+ <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
+ </ip>
+ <ip family='ipv4' address='10.24.10.1'>
+ </ip>
+</network>
diff --git a/tests/networkxml2xmlout/nat-network-dns-srv-record-minimal.xml b/tests/networkxml2xmlout/nat-network-dns-srv-record-minimal.xml
new file mode 100644
index 0000000..e9b7680
--- /dev/null
+++ b/tests/networkxml2xmlout/nat-network-dns-srv-record-minimal.xml
@@ -0,0 +1,26 @@
+<network>
+ <name>default</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward dev='eth1' mode='nat'>
+ <interface dev='eth1'/>
+ </forward>
+ <bridge name='virbr0' stp='on' delay='0' />
+ <dns>
+ <srv service='name' protocol='tcp' />
+ </dns>
+ <ip address='192.168.122.1' netmask='255.255.255.0'>
+ <dhcp>
+ <range start='192.168.122.2' end='192.168.122.254' />
+ <host mac='00:16:3e:77:e2:ed' name='a.example.com' ip='192.168.122.10' />
+ <host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11' />
+ </dhcp>
+ </ip>
+ <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
+ </ip>
+ <ip family='ipv4' address='10.24.10.1'>
+ </ip>
+</network>
diff --git a/tests/networkxml2xmlout/nat-network-dns-srv-record.xml b/tests/networkxml2xmlout/nat-network-dns-srv-record.xml
new file mode 100644
index 0000000..4be85b5
--- /dev/null
+++ b/tests/networkxml2xmlout/nat-network-dns-srv-record.xml
@@ -0,0 +1,26 @@
+<network>
+ <name>default</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward dev='eth1' mode='nat'>
+ <interface dev='eth1'/>
+ </forward>
+ <bridge name='virbr0' stp='on' delay='0' />
+ <dns>
+ <srv service='name' protocol='tcp' domain='test-domain-name' target='.' port='1024' priority='10' weight='10' />
+ </dns>
+ <ip address='192.168.122.1' netmask='255.255.255.0'>
+ <dhcp>
+ <range start='192.168.122.2' end='192.168.122.254' />
+ <host mac='00:16:3e:77:e2:ed' name='a.example.com' ip='192.168.122.10' />
+ <host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11' />
+ </dhcp>
+ </ip>
+ <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
+ </ip>
+ <ip family='ipv4' address='10.24.10.1'>
+ </ip>
+</network>
diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c
index 5cdbedb..b9f6546 100644
--- a/tests/networkxml2xmltest.c
+++ b/tests/networkxml2xmltest.c
@@ -87,6 +87,8 @@ mymain(void)
DO_TEST("netboot-network");
DO_TEST("netboot-proxy-network");
DO_TEST("nat-network-dns-txt-record");
+ DO_TEST("nat-network-dns-srv-record");
+ DO_TEST("nat-network-dns-srv-record-minimal");
DO_TEST("nat-network-dns-hosts");
DO_TEST("8021Qbh-net");
DO_TEST("direct-net");
--
1.7.4.4
13 years, 3 months
[libvirt] [PATCH v2.5] daemon: Add early libvirtd start verbose errors.
by Peter Krempa
Early errors during start of libvirtd didn't have
an error reporting mechanism and caused libvirtd
to exit silently (only the return value indicated
an error).
Libvirt logging is initialized very early using
enviroment variables and the internal error reporting
API is used to report early errors.
v2 changes:
- print errors unconditionaly before logging starts
- fix message to US spelling
v2.5 changes:
- initialize logging from enviroment
- log all early errors using VIR_ERROR
fixes: https://bugzilla.redhat.com/show_bug.cgi?id=728654
---
daemon/libvirtd.c | 41 ++++++++++++++++++++++++++++++-----------
1 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 53f1002..aa69f80 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -1285,11 +1285,14 @@ int main(int argc, char **argv) {
{0, 0, 0, 0}
};
+ /* initialize early logging */
+ virLogSetFromEnv();
+
if (setlocale (LC_ALL, "") == NULL ||
bindtextdomain (PACKAGE, LOCALEDIR) == NULL ||
textdomain(PACKAGE) == NULL ||
virInitialize() < 0) {
- fprintf(stderr, _("%s: initialization failed\n"), argv[0]);
+ VIR_ERROR(_("%s: initialization failed"), argv[0]);
exit(EXIT_FAILURE);
}
@@ -1328,14 +1331,18 @@ int main(int argc, char **argv) {
case 'p':
VIR_FREE(pid_file);
- if (!(pid_file = strdup(optarg)))
+ if (!(pid_file = strdup(optarg))) {
+ VIR_ERROR(_("Can't allocate memory"));
exit(EXIT_FAILURE);
+ }
break;
case 'f':
VIR_FREE(remote_config_file);
- if (!(remote_config_file = strdup(optarg)))
+ if (!(remote_config_file = strdup(optarg))) {
+ VIR_ERROR(_("Can't allocate memory"));
exit(EXIT_FAILURE);
+ }
break;
case OPT_VERSION:
@@ -1347,27 +1354,33 @@ int main(int argc, char **argv) {
return 2;
default:
- fprintf (stderr, _("%s: internal error: unknown flag: %c\n"),
- argv[0], c);
+ VIR_ERROR(_("%s: internal error: unknown flag: %c"),
+ argv[0], c);
exit (EXIT_FAILURE);
}
}
- if (!(config = daemonConfigNew(privileged)))
+ if (!(config = daemonConfigNew(privileged))) {
+ VIR_ERROR(_("Can't create initial configuration"));
exit(EXIT_FAILURE);
+ }
/* No explicit config, so try and find a default one */
if (remote_config_file == NULL) {
implicit_conf = true;
if (daemonConfigFilePath(privileged,
- &remote_config_file) < 0)
+ &remote_config_file) < 0) {
+ VIR_ERROR(_("Can't determine config path"));
exit(EXIT_FAILURE);
+ }
}
/* Read the config file if it exists*/
if (remote_config_file &&
- daemonConfigLoad(config, remote_config_file, implicit_conf) < 0)
+ daemonConfigLoad(config, remote_config_file, implicit_conf) < 0) {
+ VIR_ERROR(_("Can't load config file '%s'"), remote_config_file);
exit(EXIT_FAILURE);
+ }
if (config->host_uuid &&
virSetHostUUIDStr(config->host_uuid) < 0) {
@@ -1375,19 +1388,25 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE);
}
- if (daemonSetupLogging(config, privileged, verbose, godaemon) < 0)
+ if (daemonSetupLogging(config, privileged, verbose, godaemon) < 0) {
+ VIR_ERROR(_("Can't initialize logging"));
exit(EXIT_FAILURE);
+ }
if (!pid_file && privileged &&
daemonPidFilePath(privileged,
- &pid_file) < 0)
+ &pid_file) < 0) {
+ VIR_ERROR(_("Can't determine pid file path."));
exit(EXIT_FAILURE);
+ }
if (daemonUnixSocketPaths(config,
privileged,
&sock_file,
- &sock_file_ro) < 0)
+ &sock_file_ro) < 0) {
+ VIR_ERROR(_("Can't determine socket paths"));
exit(EXIT_FAILURE);
+ }
if (godaemon) {
char ebuf[1024];
--
1.7.6
13 years, 3 months
[libvirt] [PATCH v3] Add support for fd: protocol
by Corey Bryant
sVirt provides SELinux MAC isolation for Qemu guest processes and their
corresponding resources (image files). sVirt provides this support
by labeling guests and resources with security labels that are stored
in file system extended attributes. Some file systems, such as NFS, do
not support the extended attribute security namespace, which is needed
for image file isolation when using the sVirt SELinux security driver
in libvirt.
The proposed solution entails a combination of Qemu, libvirt, and
SELinux patches that work together to isolate multiple guests' images
when they're stored in the same NFS mount. This results in an
environment where sVirt isolation and NFS image file isolation can both
be provided.
This patch contains the Qemu code to support this solution. I would
like to solicit input from the libvirt community prior to starting
the libvirt patch.
Currently, Qemu opens an image file in addition to performing the
necessary read and write operations. The proposed solution will move
the open out of Qemu and into libvirt. Once libvirt opens an image
file for the guest, it will pass the file descriptor to Qemu via a
new fd: protocol.
If the image file resides in an NFS mount, the following SELinux policy
changes will provide image isolation:
- A new SELinux boolean is created (e.g. virt_read_write_nfs) to
allow Qemu (svirt_t) to only have SELinux read and write
permissions on nfs_t files
- Qemu (svirt_t) also gets SELinux use permissions on libvirt
(virtd_t) file descriptors
Following is a sample invocation of Qemu using the fd: protocol on
the command line:
qemu -drive file=fd:4,format=qcow2
The fd: protocol is also supported by the drive_add monitor command.
This requires that the specified file descriptor is passed to the
monitor alongside a prior getfd monitor command.
There are some additional features provided by certain image types
where Qemu reopens the image file. All of these scenarios will be
unsupported for the fd: protocol, at least for this patch:
- The -snapshot command line option
- The savevm monitor command
- The snapshot_blkdev monitor command
- Use of copy-on-write image files
- The -cdrom command line option
- The -drive command line option with media=cdrom
- The change monitor command
The thought is that this support can be added in the future, but is
not required for the initial fd: support.
This patch was tested with the following formats: raw, cow, qcow,
qcow2, qed, and vmdk, using the fd: protocol from the command line
and the monitor. Tests were also run to verify existing file name
support and qemu-img were not regressed. Non-valid file descriptors,
fd: without format, snapshot and backing files, and cdrom were also
tested.
v2:
- Add drive_add monitor command support
- Fence off unsupported features that re-open image file
v3:
- Fence off cdrom and change monitor command support
Signed-off-by: Corey Bryant <coreyb(a)linux.vnet.ibm.com>
---
block.c | 16 ++++++++++
block.h | 1 +
block/cow.c | 5 +++
block/qcow.c | 5 +++
block/qcow2.c | 5 +++
block/qed.c | 4 ++
block/raw-posix.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++------
block/vmdk.c | 5 +++
block_int.h | 1 +
blockdev.c | 19 ++++++++++++
monitor.c | 5 +++
monitor.h | 1 +
qemu-options.hx | 8 +++--
qemu-tool.c | 5 +++
14 files changed, 149 insertions(+), 12 deletions(-)
diff --git a/block.c b/block.c
index 24a25d5..500db84 100644
--- a/block.c
+++ b/block.c
@@ -536,6 +536,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
char tmp_filename[PATH_MAX];
char backing_filename[PATH_MAX];
+ if (bdrv_is_fd_protocol(bs)) {
+ return -ENOTSUP;
+ }
+
/* if snapshot, we create a temporary backing file and open it
instead of opening 'filename' directly */
@@ -585,6 +589,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
/* Find the right image format driver */
if (!drv) {
+ /* format must be specified for fd: protocol */
+ if (bdrv_is_fd_protocol(bs)) {
+ return -ENOTSUP;
+ }
ret = find_image_format(filename, &drv);
}
@@ -1460,6 +1468,11 @@ int bdrv_enable_write_cache(BlockDriverState *bs)
return bs->enable_write_cache;
}
+int bdrv_is_fd_protocol(BlockDriverState *bs)
+{
+ return bs->fd_protocol;
+}
+
/* XXX: no longer used */
void bdrv_set_change_cb(BlockDriverState *bs,
void (*change_cb)(void *opaque, int reason),
@@ -1964,6 +1977,9 @@ int bdrv_snapshot_create(BlockDriverState *bs,
BlockDriver *drv = bs->drv;
if (!drv)
return -ENOMEDIUM;
+ if (bdrv_is_fd_protocol(bs)) {
+ return -ENOTSUP;
+ }
if (drv->bdrv_snapshot_create)
return drv->bdrv_snapshot_create(bs, sn_info);
if (bs->file)
diff --git a/block.h b/block.h
index 859d1d9..0417b69 100644
--- a/block.h
+++ b/block.h
@@ -182,6 +182,7 @@ int bdrv_is_removable(BlockDriverState *bs);
int bdrv_is_read_only(BlockDriverState *bs);
int bdrv_is_sg(BlockDriverState *bs);
int bdrv_enable_write_cache(BlockDriverState *bs);
+int bdrv_is_fd_protocol(BlockDriverState *bs);
int bdrv_is_inserted(BlockDriverState *bs);
int bdrv_media_changed(BlockDriverState *bs);
int bdrv_is_locked(BlockDriverState *bs);
diff --git a/block/cow.c b/block/cow.c
index 4cf543c..e17f8e7 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -82,6 +82,11 @@ static int cow_open(BlockDriverState *bs, int flags)
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
cow_header.backing_file);
+ if (bs->backing_file[0] != '\0' && bdrv_is_fd_protocol(bs)) {
+ /* backing file currently not supported by fd: protocol */
+ goto fail;
+ }
+
bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
s->cow_sectors_offset = (bitmap_size + 511) & ~511;
return 0;
diff --git a/block/qcow.c b/block/qcow.c
index 227b104..964d411 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -157,6 +157,11 @@ static int qcow_open(BlockDriverState *bs, int flags)
if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len)
goto fail;
bs->backing_file[len] = '\0';
+
+ if (bs->backing_file[0] != '\0' && bdrv_is_fd_protocol(bs)) {
+ /* backing file currently not supported by fd: protocol */
+ goto fail;
+ }
}
return 0;
diff --git a/block/qcow2.c b/block/qcow2.c
index 48e1b95..7f6a4fa 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -270,6 +270,11 @@ static int qcow2_open(BlockDriverState *bs, int flags)
goto fail;
}
bs->backing_file[len] = '\0';
+
+ if (bs->backing_file[0] != '\0' && bdrv_is_fd_protocol(bs)) {
+ ret = -ENOTSUP;
+ goto fail;
+ }
}
if (qcow2_read_snapshots(bs) < 0) {
ret = -EINVAL;
diff --git a/block/qed.c b/block/qed.c
index 3970379..5028897 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -446,6 +446,10 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
return ret;
}
+ if (bs->backing_file[0] != '\0' && bdrv_is_fd_protocol(bs)) {
+ return -ENOTSUP;
+ }
+
if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) {
pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw");
}
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 34b64aa..cec4d36 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -28,6 +28,7 @@
#include "block_int.h"
#include "module.h"
#include "block/raw-posix-aio.h"
+#include "monitor.h"
#ifdef CONFIG_COCOA
#include <paths.h>
@@ -185,7 +186,8 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
int bdrv_flags, int open_flags)
{
BDRVRawState *s = bs->opaque;
- int fd, ret;
+ int fd = -1;
+ int ret;
ret = raw_normalize_devicepath(&filename);
if (ret != 0) {
@@ -207,15 +209,17 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
if (!(bdrv_flags & BDRV_O_CACHE_WB))
s->open_flags |= O_DSYNC;
- s->fd = -1;
- fd = qemu_open(filename, s->open_flags, 0644);
- if (fd < 0) {
- ret = -errno;
- if (ret == -EROFS)
- ret = -EACCES;
- return ret;
+ if (s->fd == -1) {
+ fd = qemu_open(filename, s->open_flags, 0644);
+ if (fd < 0) {
+ ret = -errno;
+ if (ret == -EROFS) {
+ ret = -EACCES;
+ }
+ return ret;
+ }
+ s->fd = fd;
}
- s->fd = fd;
s->aligned_buf = NULL;
if ((bdrv_flags & BDRV_O_NOCACHE)) {
@@ -272,6 +276,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
+ s->fd = -1;
s->type = FTYPE_FILE;
return raw_open_common(bs, filename, flags, 0);
}
@@ -892,6 +897,60 @@ static BlockDriver bdrv_file = {
.create_options = raw_create_options,
};
+static int raw_open_fd(BlockDriverState *bs, const char *filename, int flags)
+{
+ BDRVRawState *s = bs->opaque;
+ const char *fd_str;
+ int fd;
+
+ /* extract the file descriptor - fail if it's not fd: */
+ if (!strstart(filename, "fd:", &fd_str)) {
+ return -EINVAL;
+ }
+
+ if (!qemu_isdigit(fd_str[0])) {
+ /* get fd from monitor */
+ fd = qemu_get_fd(fd_str);
+ if (fd == -1) {
+ return -EBADF;
+ }
+ } else {
+ char *endptr = NULL;
+
+ fd = strtol(fd_str, &endptr, 10);
+ if (*endptr || (fd == 0 && fd_str == endptr)) {
+ return -EBADF;
+ }
+ }
+
+ s->fd = fd;
+ s->type = FTYPE_FILE;
+
+ return raw_open_common(bs, filename, flags, 0);
+}
+
+static BlockDriver bdrv_file_fd = {
+ .format_name = "file",
+ .protocol_name = "fd",
+ .instance_size = sizeof(BDRVRawState),
+ .bdrv_probe = NULL, /* no probe for protocols */
+ .bdrv_file_open = raw_open_fd,
+ .bdrv_read = raw_read,
+ .bdrv_write = raw_write,
+ .bdrv_close = raw_close,
+ .bdrv_flush = raw_flush,
+ .bdrv_discard = raw_discard,
+
+ .bdrv_aio_readv = raw_aio_readv,
+ .bdrv_aio_writev = raw_aio_writev,
+ .bdrv_aio_flush = raw_aio_flush,
+
+ .bdrv_truncate = raw_truncate,
+ .bdrv_getlength = raw_getlength,
+
+ .create_options = raw_create_options,
+};
+
/***********************************************/
/* host device */
@@ -1000,6 +1059,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
}
#endif
+ s->fd = -1;
s->type = FTYPE_FILE;
#if defined(__linux__)
{
@@ -1170,6 +1230,7 @@ static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
BDRVRawState *s = bs->opaque;
int ret;
+ s->fd = -1;
s->type = FTYPE_FD;
/* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
@@ -1288,6 +1349,7 @@ static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
+ s->fd = -1;
s->type = FTYPE_CD;
/* open will not fail even if no CD is inserted, so add O_NONBLOCK */
@@ -1517,6 +1579,7 @@ static void bdrv_file_init(void)
* Register all the drivers. Note that order is important, the driver
* registered last will get probed first.
*/
+ bdrv_register(&bdrv_file_fd);
bdrv_register(&bdrv_file);
bdrv_register(&bdrv_host_device);
#ifdef __linux__
diff --git a/block/vmdk.c b/block/vmdk.c
index 922b23d..2ea808e 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -353,6 +353,11 @@ static int vmdk_parent_open(BlockDriverState *bs)
return -1;
pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
+
+ if (bs->backing_file[0] != '\0' && bdrv_is_fd_protocol(bs)) {
+ /* backing file currently not supported by fd: protocol */
+ return -1;
+ }
}
return 0;
diff --git a/block_int.h b/block_int.h
index 1e265d2..441049c 100644
--- a/block_int.h
+++ b/block_int.h
@@ -152,6 +152,7 @@ struct BlockDriverState {
int encrypted; /* if true, the media is encrypted */
int valid_key; /* if true, a valid encryption key has been set */
int sg; /* if true, the device is a /dev/sg* */
+ int fd_protocol; /* if true, the fd: protocol was specified */
/* event callback when inserting/removing */
void (*change_cb)(void *opaque, int reason);
void *change_opaque;
diff --git a/blockdev.c b/blockdev.c
index c263663..5cb7b56 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -542,6 +542,14 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
+ if (strncmp(file, "fd:", 3) == 0) {
+ if (media == MEDIA_CDROM) {
+ error_report("CD-ROM not supported by fd: protocol");
+ goto err;
+ }
+ dinfo->bdrv->fd_protocol = 1;
+ }
+
ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv);
if (ret < 0) {
error_report("could not open disk image %s: %s",
@@ -602,6 +610,12 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
goto out;
}
+ if (bdrv_is_fd_protocol(bs)) {
+ qerror_report(QERR_UNSUPPORTED);
+ ret = -1;
+ goto out;
+ }
+
pstrcpy(old_filename, sizeof(old_filename), bs->filename);
old_drv = bs->drv;
@@ -719,6 +733,11 @@ int do_change_block(Monitor *mon, const char *device,
BlockDriver *drv = NULL;
int bdrv_flags;
+ if (strncmp(filename, "fd:", 3) == 0) {
+ qerror_report(QERR_UNSUPPORTED);
+ return -1;
+ }
+
bs = bdrv_find(device);
if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, device);
diff --git a/monitor.c b/monitor.c
index a6388a9..e521b60 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2832,6 +2832,11 @@ int monitor_get_fd(Monitor *mon, const char *fdname)
return -1;
}
+int qemu_get_fd(const char *fdname)
+{
+ return cur_mon ? monitor_get_fd(cur_mon, fdname) : -1;
+}
+
static const mon_cmd_t mon_cmds[] = {
#include "hmp-commands.h"
{ NULL, NULL, },
diff --git a/monitor.h b/monitor.h
index 4f2d328..de5b987 100644
--- a/monitor.h
+++ b/monitor.h
@@ -51,6 +51,7 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
void *opaque);
int monitor_get_fd(Monitor *mon, const char *fdname);
+int qemu_get_fd(const char *fdname);
void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
GCC_FMT_ATTR(2, 0);
diff --git a/qemu-options.hx b/qemu-options.hx
index cb3347e..ab28541 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -116,7 +116,7 @@ using @file{/dev/cdrom} as filename (@pxref{host_drives}).
ETEXI
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
- "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
+ "-drive [file=[fd:]file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
" [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
" [,cache=writethrough|writeback|none|unsafe][,format=f]\n"
" [,serial=s][,addr=A][,id=name][,aio=threads|native]\n"
@@ -129,10 +129,12 @@ STEXI
Define a new drive. Valid options are:
@table @option
-@item file=@var{file}
+@item file=[fd:]@var{file}
This option defines which disk image (@pxref{disk_images}) to use with
this drive. If the filename contains comma, you must double it
-(for instance, "file=my,,file" to use file "my,file").
+(for instance, "file=my,,file" to use file "my,file"). @option{fd:}@var{file}
+specifies the file descriptor of an already open disk image.
+@option{format=}@var{format} is required by @option{fd:}@var{file}.
@item if=@var{interface}
This option defines on which type on interface the drive is connected.
Available types are: ide, scsi, sd, mtd, floppy, pflash, virtio.
diff --git a/qemu-tool.c b/qemu-tool.c
index 41e5c41..8fe6b8c 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -96,3 +96,8 @@ int64_t qemu_get_clock_ns(QEMUClock *clock)
{
return 0;
}
+
+int qemu_get_fd(const char *fdname)
+{
+ return -1;
+}
--
1.7.3.4
13 years, 3 months
[libvirt] [PATCH] daemon: Add early libvirtd start verbose errors.
by Peter Krempa
Early errors during start of libvirtd didn't have
an error reporting mechanism and caused libvirtd
to exit silently (only the return value indicated
an error). This patch adds error messages printed
to stderr if verbose parameter is specified to the
daemon.
fixes: https://bugzilla.redhat.com/show_bug.cgi?id=728654
---
daemon/libvirtd.c | 40 ++++++++++++++++++++++++++++++++--------
1 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 53f1002..c3867af 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -1328,14 +1328,20 @@ int main(int argc, char **argv) {
case 'p':
VIR_FREE(pid_file);
- if (!(pid_file = strdup(optarg)))
+ if (!(pid_file = strdup(optarg))) {
+ if (verbose)
+ fprintf(stderr, _("ERROR: Can't allocate memory\n"));
exit(EXIT_FAILURE);
+ }
break;
case 'f':
VIR_FREE(remote_config_file);
- if (!(remote_config_file = strdup(optarg)))
+ if (!(remote_config_file = strdup(optarg))) {
+ if (verbose)
+ fprintf(stderr, _("ERROR: Can't allocate memory\n"));
exit(EXIT_FAILURE);
+ }
break;
case OPT_VERSION:
@@ -1353,21 +1359,30 @@ int main(int argc, char **argv) {
}
}
- if (!(config = daemonConfigNew(privileged)))
+ if (!(config = daemonConfigNew(privileged))) {
+ if (verbose)
+ fprintf(stderr, _("ERROR: Can't create configuration\n"));
exit(EXIT_FAILURE);
+ }
/* No explicit config, so try and find a default one */
if (remote_config_file == NULL) {
implicit_conf = true;
if (daemonConfigFilePath(privileged,
- &remote_config_file) < 0)
+ &remote_config_file) < 0) {
+ if (verbose)
+ fprintf(stderr, _("ERROR: Can't determine config path\n"));
exit(EXIT_FAILURE);
+ }
}
/* Read the config file if it exists*/
if (remote_config_file &&
- daemonConfigLoad(config, remote_config_file, implicit_conf) < 0)
+ daemonConfigLoad(config, remote_config_file, implicit_conf) < 0) {
+ if (verbose)
+ fprintf(stderr, _("ERROR: Can't load config file '%s'\n"), remote_config_file);
exit(EXIT_FAILURE);
+ }
if (config->host_uuid &&
virSetHostUUIDStr(config->host_uuid) < 0) {
@@ -1375,19 +1390,28 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE);
}
- if (daemonSetupLogging(config, privileged, verbose, godaemon) < 0)
+ if (daemonSetupLogging(config, privileged, verbose, godaemon) < 0) {
+ if (verbose)
+ fprintf(stderr, _("ERROR: Can't initialise logging\n"));
exit(EXIT_FAILURE);
+ }
+
+ /* error logging is up, use libvirt's error logging from now */
if (!pid_file && privileged &&
daemonPidFilePath(privileged,
- &pid_file) < 0)
+ &pid_file) < 0) {
+ VIR_ERROR(_("Can't determine pid file path."));
exit(EXIT_FAILURE);
+ }
if (daemonUnixSocketPaths(config,
privileged,
&sock_file,
- &sock_file_ro) < 0)
+ &sock_file_ro) < 0) {
+ VIR_ERROR(_("Can't determine socket paths"));
exit(EXIT_FAILURE);
+ }
if (godaemon) {
char ebuf[1024];
--
1.7.6
13 years, 3 months
[libvirt] [PATCH] Bugfix: Check stdoutWatch before removing the handler.
by Juerg Haefliger
---
tools/console.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tools/console.c b/tools/console.c
index 11087e5..171ebc9 100644
--- a/tools/console.c
+++ b/tools/console.c
@@ -95,7 +95,7 @@ virConsoleShutdown(virConsolePtr con)
virStreamFree(con->st);
if (con->stdinWatch != -1)
virEventRemoveHandle(con->stdinWatch);
- if (con->stdinWatch != -1)
+ if (con->stdoutWatch != -1)
virEventRemoveHandle(con->stdoutWatch);
con->stdinWatch = -1;
con->stdoutWatch = -1;
--
1.7.4.1
13 years, 3 months
[libvirt] [PATCH] virsh: add snapshot-parent
by Eric Blake
Down the road, I want to add virDomainSnapshotGetParent, and use
the new API rather than xml scraping; but this virsh command can
be implemented even without the new API.
* tools/virsh.c (cmdSnapshotParent): New command.
* tools/virsh.pod (snapshot-parent): Document it.
---
Adding this will make it a bit easier to track relationships between
snapshots, especially since 'virsh snapshot-list' covers everything
except the relationship.
tools/virsh.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/virsh.pod | 4 +++
2 files changed, 82 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 1d660d0..ee08c01 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -12285,6 +12285,82 @@ cleanup:
}
/*
+ * "snapshot-parent" command
+ */
+static const vshCmdInfo info_snapshot_parent[] = {
+ {"help", N_("Get the name of the parent of the current snapshot")},
+ {"desc", N_("Extract the snapshot's parent, if any")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_snapshot_parent[] = {
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
+ {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")},
+ {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdSnapshotParent(vshControl *ctl, const vshCmd *cmd)
+{
+ virDomainPtr dom = NULL;
+ bool ret = false;
+ const char *name = NULL;
+ virDomainSnapshotPtr snapshot = NULL;
+ char *xml = NULL;
+ char *parent = NULL;
+ xmlDocPtr xmldoc = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+
+ if (!vshConnectionUsability(ctl, ctl->conn))
+ goto cleanup;
+
+ dom = vshCommandOptDomain(ctl, cmd, NULL);
+ if (dom == NULL)
+ goto cleanup;
+
+ if (vshCommandOptString(cmd, "snapshotname", &name) <= 0)
+ goto cleanup;
+
+ snapshot = virDomainSnapshotLookupByName(dom, name, 0);
+ if (snapshot == NULL)
+ goto cleanup;
+
+ xml = virDomainSnapshotGetXMLDesc(snapshot, 0);
+ if (!xml)
+ goto cleanup;
+
+ xmldoc = xmlReadDoc((const xmlChar *) xml, "domainsnapshot.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ if (!xmldoc)
+ goto cleanup;
+ ctxt = xmlXPathNewContext(xmldoc);
+ if (!ctxt)
+ goto cleanup;
+
+ parent = virXPathString("string(/domainsnapshot/parent/name)", ctxt);
+ if (!parent)
+ goto cleanup;
+
+ vshPrint(ctl, "%s", parent);
+
+ ret = true;
+
+cleanup:
+ VIR_FREE(parent);
+ xmlXPathFreeContext(ctxt);
+ if (xmldoc)
+ xmlFreeDoc(xmldoc);
+ VIR_FREE(xml);
+ if (snapshot)
+ virDomainSnapshotFree(snapshot);
+ if (dom)
+ virDomainFree(dom);
+
+ return ret;
+}
+
+/*
* "snapshot-revert" command
*/
static const vshCmdInfo info_snapshot_revert[] = {
@@ -12754,6 +12830,8 @@ static const vshCmdDef snapshotCmds[] = {
info_snapshot_dumpxml, 0},
{"snapshot-list", cmdSnapshotList, opts_snapshot_list,
info_snapshot_list, 0},
+ {"snapshot-parent", cmdSnapshotParent, opts_snapshot_parent,
+ info_snapshot_parent, 0},
{"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert,
info_snapshot_revert, 0},
{NULL, NULL, NULL, NULL, 0}
diff --git a/tools/virsh.pod b/tools/virsh.pod
index a6af1e6..1893c23 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1583,6 +1583,10 @@ List all of the available snapshots for the given domain.
Output the snapshot XML for the domain's snapshot named I<snapshot>.
+=item B<snapshot-parent> I<domain> I<snapshot>
+
+Output the name of the parent snapshot for the given I<snapshot>, if any.
+
=item B<snapshot-revert> I<domain> I<snapshot>
Revert the given domain to the snapshot specified by I<snapshot>. Be aware
--
1.7.4.4
13 years, 3 months
[libvirt] [PATCH] qemu: avoid dereference of null pointer
by ajia@redhat.com
* src/qemu/qemu_driver.c: avoid dereference of null pointer.
Signed-off-by: Alex Jia <ajia(a)redhat.com>
---
src/qemu/qemu_driver.c | 27 ++++++++++++++++++---------
1 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ce19be7..28ffff7 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5697,7 +5697,8 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
continue;
}
- persistentDef->blkio.weight = params[i].value.ui;
+ if (params[i].value.ul)
+ persistentDef->blkio.weight = params[i].value.ui;
} else {
qemuReportError(VIR_ERR_INVALID_ARG,
_("Parameter `%s' not supported"), param->field);
@@ -5837,7 +5838,8 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
"%s", _("Field blkio weight too long for destination"));
goto cleanup;
}
- param->value.ui = persistentDef->blkio.weight;
+ if (persistentDef->blkio.weight)
+ param->value.ui = persistentDef->blkio.weight;
break;
default:
@@ -5946,7 +5948,8 @@ static int qemuDomainSetMemoryParameters(virDomainPtr dom,
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- persistentDef->mem.hard_limit = params[i].value.ul;
+ if (params[i].value.ul)
+ persistentDef->mem.hard_limit = params[i].value.ul;
}
} else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
int rc;
@@ -5967,7 +5970,8 @@ static int qemuDomainSetMemoryParameters(virDomainPtr dom,
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- persistentDef->mem.soft_limit = params[i].value.ul;
+ if (params[i].value.ul)
+ persistentDef->mem.soft_limit = params[i].value.ul;
}
} else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
int rc;
@@ -5987,7 +5991,8 @@ static int qemuDomainSetMemoryParameters(virDomainPtr dom,
}
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- persistentDef->mem.swap_hard_limit = params[i].value.ul;
+ if (params[i].value.ul)
+ persistentDef->mem.swap_hard_limit = params[i].value.ul;
}
} else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
qemuReportError(VIR_ERR_INVALID_ARG,
@@ -6107,7 +6112,8 @@ static int qemuDomainGetMemoryParameters(virDomainPtr dom,
"%s", _("Field memory hard limit too long for destination"));
goto cleanup;
}
- param->value.ul = persistentDef->mem.hard_limit;
+ if (persistentDef->mem.hard_limit)
+ param->value.ul = persistentDef->mem.hard_limit;
break;
case 1: /* fill memory soft limit here */
@@ -6404,7 +6410,8 @@ static int qemuSetSchedulerParametersFlags(virDomainPtr dom,
goto cleanup;
}
- vm->def->cputune.shares = params[i].value.ul;
+ if (params[i].value.ul)
+ vm->def->cputune.shares = params[i].value.ul;
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
@@ -6428,7 +6435,8 @@ static int qemuSetSchedulerParametersFlags(virDomainPtr dom,
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- vmdef->cputune.period = params[i].value.ul;
+ if (params[i].value.ul)
+ vmdef->cputune.period = params[i].value.ul;
}
} else if (STREQ(param->field, "vcpu_quota")) {
if (param->type != VIR_TYPED_PARAM_LLONG) {
@@ -6448,7 +6456,8 @@ static int qemuSetSchedulerParametersFlags(virDomainPtr dom,
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- vmdef->cputune.quota = params[i].value.l;
+ if (params[i].value.ul)
+ vmdef->cputune.quota = params[i].value.l;
}
} else {
qemuReportError(VIR_ERR_INVALID_ARG,
--
1.7.5.1
13 years, 3 months
[libvirt] [PATCH] conf: eliminate redundat VIR_ALLOC of first element of hosts.
by Laine Stump
virNetworkDNSHostsDefParseXML was calling VIR_ALLOC(def->hosts) if
def->nhosts was 0. This is a waste of time, though, since
VIR_REALLOC_N is called a few lines further down, prior to any use of
def->hosts.
---
src/conf/network_conf.c | 8 --------
1 files changed, 0 insertions(+), 8 deletions(-)
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index e055094..109739f 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -495,14 +495,6 @@ virNetworkDNSHostsDefParseXML(virNetworkDNSDefPtr def,
virSocketAddr inaddr;
int ret = -1;
- if (def->hosts == NULL) {
- if (VIR_ALLOC(def->hosts) < 0) {
- virReportOOMError();
- goto error;
- }
- def->nhosts = 0;
- }
-
if (!(ip = virXMLPropString(node, "ip")) ||
(virSocketParseAddr(ip, &inaddr, AF_UNSPEC) < 0)) {
virNetworkReportError(VIR_ERR_XML_DETAIL,
--
1.7.3.4
13 years, 3 months
[libvirt] problem with outbound limiting
by Upendra Moturi
Hi
I am using 0.9.4 version of libvirt and want to limit bandwidth.
I installed libvirt on ubuntu 11.04 using libvirt source.
For this i am using the QOS configuration
<devices>
<interface type='network'>
<source network='default'/>
<target dev='vnet0'/>
*<bandwidth>
<inbound average='1000' peak='5000' burst='1024'/>
<outbound average='128' peak='256' burst='256'/>
</bandwidth>*
</interface>
Here the inbound limit is working properly but the outbound is limiting but
not with values which is give
Here are the scenarios i tested and the results
when i gave average as 2048 --- it is limiting with 600 -- 700 kb
average result
=====================
2048 (2mpbs) 600-700 kb
4096 (4mbps) 1 MB/s
10240 (10mbps) 2-3 MB/s
12288 (12 mbps) 3-4 MB/s
20480 (20 mbps) 16-18 MB/s
Is this the expected behavior or some thing is missing
If this is the expected behavior ,then in what ratio it is limiting.
Please help me
Thanks in advance.
--
Thanks and Regards,
Upendra.M
13 years, 3 months