<pre>
...
<mac address='00:16:3E:5D:C7:9E'/>
+ <dns>
+ <txt name="example" value="example value" />
+ </dns>
<ip address="192.168.122.1" netmask="255.255.255.0">
<dhcp>
<range start="192.168.122.100" end="192.168.122.254" />
supported for IPv6 addresses, can only be specified on a single IPv4 address
per network.
<span class="since">Since 0.7.1</span>
- </dd><dt><code>dhcp</code></dt><dd>Also within the <code>ip</code> element there is an
+ </dd>
+
+ <dt><code>dns</code></dt><dd>
+ The dns element of a network contains configuration information for the
+ virtual network's DNS server. <span class="since">Since 0.9.3</span>
+ Currently supported elements are:
+ <dl>
+ <dt><code>txt</code></dt>
+ <dd>A <code>dns</code> element can have 0 or more <code>txt</code> elements.
+ Each txt element defines a DNS TXT record and has two attributes, both
+ required: a name that can be queried via dns, and a value that will be
+ returned when that name is queried. names cannot contain embedded spaces
+ or commas. value is a single string that can contain multiple values
+ separated by commas. <span class="since">Since 0.9.3</span>
+ </dd>
+ </dl>
+ </dd>
+ <dt><code>dhcp</code></dt>
+ <dd>Also within the <code>ip</code> element there is an
optional <code>dhcp</code> element. The presence of this element
enables DHCP services on the virtual network. It will further
contain one or more <code>range</code> elements. The
</element>
</optional>
+ <!-- Define the DNS related elements like TXT records
+ and other features in the <dns> element -->
+ <optional>
+ <element name="dns">
+ <zeroOrMore>
+ <element name="txt">
+ <attribute name="name"><ref name="dns-name"/></attribute>
+ <attribute name="value"><text/></attribute>
+ </element>
+ </zeroOrMore>
+ </element>
+ </optional>
+
<!-- <ip> element -->
<zeroOrMore>
<!-- The IP element sets up NAT'ing and an optional DHCP server
</data>
</define>
+ <!-- a valid DNS name -->
+ <define name='dns-name'>
+ <data type='string'>
+ <param name="pattern">([a-zA-Z\-]+)</param>
+ </data>
+ </define>
+
</grammar>
VIR_FREE(def->bootfile);
}
+static void virNetworkDNSDefFree(virNetworkDNSDefPtr def)
+{
+ if (def) {
+ if (def->txtrecords) {
+ while (def->ntxtrecords--) {
+ VIR_FREE(def->txtrecords[def->ntxtrecords].name);
+ VIR_FREE(def->txtrecords[def->ntxtrecords].value);
+ }
+ VIR_FREE(def->txtrecords);
+ }
+ VIR_FREE(def);
+ }
+}
+
void virNetworkDefFree(virNetworkDefPtr def)
{
int ii;
}
VIR_FREE(def->ips);
+ virNetworkDNSDefFree(def->dns);
+
VIR_FREE(def);
}
return 0;
}
+static int
+virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef,
+ xmlNodePtr node)
+{
+ xmlNodePtr cur;
+ int ret = -1;
+ char *name = NULL;
+ char *value = NULL;
+ virNetworkDNSDefPtr def = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(cur->name, BAD_CAST "txt")) {
+ if (!(name = virXMLPropString(cur, "name"))) {
+ virNetworkReportError(VIR_ERR_XML_DETAIL,
+ "%s", _("Missing required name attribute in dns txt record"));
+ goto error;
+ }
+ if (!(value = virXMLPropString(cur, "value"))) {
+ virNetworkReportError(VIR_ERR_XML_DETAIL,
+ _("Missing required value attribute in dns txt record '%s'"), name);
+ goto error;
+ }
+
+ if (strchr(name, ' ') != NULL) {
+ virNetworkReportError(VIR_ERR_XML_DETAIL,
+ _("spaces are not allowed in DNS TXT record names (name is '%s')"), name);
+ goto error;
+ }
+
+ if (VIR_REALLOC_N(def->txtrecords, def->ntxtrecords + 1) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+
+ def->txtrecords[def->ntxtrecords].name = name;
+ def->txtrecords[def->ntxtrecords].value = value;
+ def->ntxtrecords++;
+ name = NULL;
+ value = NULL;
+ }
+
+ cur = cur->next;
+ }
+
+ ret = 0;
+error:
+ if (ret < 0) {
+ VIR_FREE(name);
+ VIR_FREE(value);
+ virNetworkDNSDefFree(def);
+ } else {
+ *dnsdef = def;
+ }
+ return ret;
+}
+
static int
virNetworkIPParseXML(const char *networkName,
virNetworkIpDefPtr def,
virNetworkDefPtr def;
char *tmp;
xmlNodePtr *ipNodes = NULL;
+ xmlNodePtr dnsNode = NULL;
int nIps;
if (VIR_ALLOC(def) < 0) {
def->mac_specified = true;
}
+ dnsNode = virXPathNode("./dns", ctxt);
+ if (dnsNode != NULL) {
+ if (virNetworkDNSDefParseXML(&def->dns, dnsNode) < 0)
+ goto error;
+ }
+
nIps = virXPathNodeSet("./ip", ctxt, &ipNodes);
if (nIps < 0)
goto error;
return def;
}
+static int
+virNetworkDNSDefFormat(virBufferPtr buf,
+ virNetworkDNSDefPtr def)
+{
+ int result = 0;
+ int i;
+
+ if (def == NULL)
+ goto out;
+
+ virBufferAddLit(buf, " <dns>\n");
+
+ for (i = 0 ; i < def->ntxtrecords ; i++) {
+ virBufferAsprintf(buf, " <txt name='%s' value='%s' />\n",
+ def->txtrecords[i].name,
+ def->txtrecords[i].value);
+ }
+
+ virBufferAddLit(buf, " </dns>\n");
+out:
+ return result;
+}
+
static int
virNetworkIpDefFormat(virBufferPtr buf,
const virNetworkIpDefPtr def)
if (def->domain)
virBufferAsprintf(&buf, " <domain name='%s'/>\n", def->domain);
+ if (virNetworkDNSDefFormat(&buf, def->dns) < 0)
+ goto error;
+
for (ii = 0; ii < def->nips; ii++) {
if (virNetworkIpDefFormat(&buf, &def->ips[ii]) < 0)
goto error;
virSocketAddr ip;
};
+typedef struct _virNetworkDNSTxtRecordsDef virNetworkDNSTxtRecordsDef;
+typedef virNetworkDNSTxtRecordsDef *virNetworkDNSTxtRecordsDefPtr;
+struct _virNetworkDNSTxtRecordsDef {
+ char *name;
+ char *value;
+};
+
+struct virNetworkDNSDef {
+ unsigned int ntxtrecords;
+ virNetworkDNSTxtRecordsDefPtr txtrecords;
+} virNetworkDNSDef;
+
+typedef struct virNetworkDNSDef *virNetworkDNSDefPtr;
+
typedef struct _virNetworkIpDef virNetworkIpDef;
typedef virNetworkIpDef *virNetworkIpDefPtr;
struct _virNetworkIpDef {
size_t nips;
virNetworkIpDefPtr ips; /* ptr to array of IP addresses on this network */
+
+ virNetworkDNSDefPtr dns; /* ptr to dns related configuration */
};
typedef struct _virNetworkObj virNetworkObj;
if (network->def->forwardType == VIR_NETWORK_FORWARD_NONE)
virCommandAddArg(cmd, "--dhcp-option=3");
+ if (network->def->dns != NULL) {
+ virNetworkDNSDefPtr dns = network->def->dns;
+ int i;
+
+ for (i = 0; i < dns->ntxtrecords; i++) {
+ char *record = NULL;
+ if (virAsprintf(&record, "%s,%s",
+ dns->txtrecords[i].name,
+ dns->txtrecords[i].value) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ virCommandAddArgPair(cmd, "--txt-record", record);
+ VIR_FREE(record);
+ }
+ }
+
/*
* --interface does not actually work with dnsmasq < 2.47,
* due to DAD for ipv6 addresses on the interface.
--- /dev/null
+<network>
+ <name>default</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward dev='eth1' mode='nat'/>
+ <bridge name='virbr0' stp='on' delay='0' />
+ <dns>
+ <txt name='example' value='example value' />
+ </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>
--- /dev/null
+<network>
+ <name>default</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward dev='eth1' mode='nat'/>
+ <bridge name='virbr0' stp='on' delay='0' />
+ <dns>
+ <txt name='example' value='example value' />
+ </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>
DO_TEST("nat-network");
DO_TEST("netboot-network");
DO_TEST("netboot-proxy-network");
+ DO_TEST("nat-network-dns-txt-record");
return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
}