<network ipv6='yes' trustGuestRxFilters='no'>
<name>default</name>
<uuid>3e3fce45-4f53-4fa7-bb32-11f34168b82b</uuid>
+ <metadata>
+ <app1:foo xmlns:app1="http://app1.org/app1/">..</app1:foo>
+ <app2:bar xmlns:app2="http://app1.org/app2/">..</app2:bar>
+ </metadata>
...</pre>
<dl>
The format must be RFC 4122 compliant, eg <code>3e3fce45-4f53-4fa7-bb32-11f34168b82b</code>.
If omitted when defining/creating a new network, a random
UUID is generated. <span class="since">Since 0.3.0</span></dd>
+ <dd>The <code>metadata</code> node can be used by applications to
+ store custom metadata in the form of XML nodes/trees. Applications
+ must use custom namespaces on their XML nodes/trees, with only
+ one top-level element per namespace (if the application needs
+ structure, they should have sub-elements to their namespace
+ element). <span class="since">Since 2.1.0</span></dd>
<dt><code>ipv6</code></dt>
<dd>When set to <code>yes</code>, the optional parameter
<code>ipv6</code> enables
</choice>
</define>
+ <define name="metadata">
+ <element name="metadata">
+ <zeroOrMore>
+ <ref name="customElement"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="customElement">
+ <element>
+ <anyName/>
+ <zeroOrMore>
+ <choice>
+ <attribute>
+ <anyName/>
+ </attribute>
+ <text/>
+ <ref name="customElement"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
</grammar>
</element>
</define>
- <define name="metadata">
- <element name="metadata">
- <zeroOrMore>
- <ref name="customElement"/>
- </zeroOrMore>
- </element>
- </define>
-
- <define name="customElement">
- <element>
- <anyName/>
- <zeroOrMore>
- <choice>
- <attribute>
- <anyName/>
- </attribute>
- <text/>
- <ref name="customElement"/>
- </choice>
- </zeroOrMore>
- </element>
- </define>
-
<!--
Type library
-->
<text/>
</element>
+ <!-- <metadata> element -->
+ <optional>
+ <ref name="metadata"/>
+ </optional>
+
<!-- <uuid> element -->
<optional>
<element name="uuid"><ref name="UUID"/></element>
virNetDevBandwidthFree(def->bandwidth);
virNetDevVlanClear(&def->vlan);
+
+ xmlFreeNode(def->metadata);
+
VIR_FREE(def);
}
xmlNodePtr save = ctxt->node;
xmlNodePtr bandwidthNode = NULL;
xmlNodePtr vlanNode;
+ xmlNodePtr metadataNode = NULL;
if (VIR_ALLOC(def) < 0)
return NULL;
}
VIR_FREE(stp);
+
+ /* Extract custom metadata */
+ if ((metadataNode = virXPathNode("./metadata[1]", ctxt)) != NULL) {
+ def->metadata = xmlCopyNode(metadataNode, 1);
+ virXMLNodeSanitizeNamespaces(def->metadata);
+ }
+
ctxt->node = save;
return def;
{
xmlDocPtr xml;
virNetworkDefPtr def = NULL;
+ int keepBlanksDefault = xmlKeepBlanksDefault(0);
if ((xml = virXMLParse(filename, xmlStr, _("(network_definition)")))) {
def = virNetworkDefParseNode(xml, xmlDocGetRootElement(xml));
xmlFreeDoc(xml);
}
+ xmlKeepBlanksDefault(keepBlanksDefault);
return def;
}
virUUIDFormat(uuid, uuidstr);
virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuidstr);
+ if (def->metadata) {
+ xmlBufferPtr xmlbuf;
+ int oldIndentTreeOutput = xmlIndentTreeOutput;
+
+ /* Indentation on output requires that we previously set
+ * xmlKeepBlanksDefault to 0 when parsing; also, libxml does 2
+ * spaces per level of indentation of intermediate elements,
+ * but no leading indentation before the starting element.
+ * Thankfully, libxml maps what looks like globals into
+ * thread-local uses, so we are thread-safe. */
+ xmlIndentTreeOutput = 1;
+ xmlbuf = xmlBufferCreate();
+ if (xmlNodeDump(xmlbuf, def->metadata->doc, def->metadata,
+ virBufferGetIndent(buf, false) / 2, 1) < 0) {
+ xmlBufferFree(xmlbuf);
+ xmlIndentTreeOutput = oldIndentTreeOutput;
+ goto error;
+ }
+ virBufferAsprintf(buf, "%s\n", (char *) xmlBufferContent(xmlbuf));
+ xmlBufferFree(xmlbuf);
+ xmlIndentTreeOutput = oldIndentTreeOutput;
+ }
+
if (def->forward.type != VIR_NETWORK_FORWARD_NONE) {
const char *dev = NULL;
if (!def->forward.npfs)
virNetDevBandwidthPtr bandwidth;
virNetDevVlan vlan;
int trustGuestRxFilters; /* enum virTristateBool */
+
+ /* Application-specific custom metadata */
+ xmlNodePtr metadata;
};
typedef struct _virNetworkObj virNetworkObj;
--- /dev/null
+<network>
+ <name>host-bridge-net</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a8e</uuid>
+ <forward mode='bridge'/>
+ <bridge name='br0'/>
+ <metadata>
+ <app1:foo xmlns:app1="http://foo.org/">fooish</app1:foo>
+ <app2:bar xmlns:app2="http://bar.com/" maman="baz">barish</app2:bar>
+ </metadata>
+</network>
--- /dev/null
+<network>
+ <name>host-bridge-net</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a8e</uuid>
+ <metadata>
+ <app1:foo xmlns:app1="http://foo.org/">fooish</app1:foo>
+ <app2:bar xmlns:app2="http://bar.com/" maman="baz">barish</app2:bar>
+ </metadata>
+ <forward mode='bridge'/>
+ <bridge name='br0'/>
+</network>
DO_TEST("host-bridge-no-flood");
DO_TEST_PARSE_ERROR("hostdev-duplicate");
DO_TEST_PARSE_ERROR("passthrough-duplicate");
+ DO_TEST("metadata");
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}