This maps to XML like: <network xmlns:dnsmasq='http://libvirt.org/schemas/network/dnsmasq/1.0'> ... <dnsmasq:options> <dnsmasq:option value="foo=bar"/> <dnsmasq:option value="cname=*.foo.example.com,master.example.com"/> </dnsmasq:options> </network> To dnsmasq config options ... foo=bar cname=*.foo.example.com,master.example.com Signed-off-by: Cole Robinson <crobinso@xxxxxxxxxx> --- docs/schemas/network.rng | 11 ++ src/network/bridge_driver.c | 130 +++++++++++++++++- src/network/bridge_driver.h | 12 ++ tests/Makefile.am | 14 +- .../networkxml2confdata/dnsmasq-options.conf | 18 +++ tests/networkxml2confdata/dnsmasq-options.xml | 15 ++ tests/networkxml2conftest.c | 8 +- tests/networkxml2xmlin/dnsmasq-options.xml | 15 ++ tests/networkxml2xmlout/dnsmasq-options.xml | 17 +++ tests/networkxml2xmltest.c | 11 +- 10 files changed, 239 insertions(+), 12 deletions(-) create mode 100644 tests/networkxml2confdata/dnsmasq-options.conf create mode 100644 tests/networkxml2confdata/dnsmasq-options.xml create mode 100644 tests/networkxml2xmlin/dnsmasq-options.xml create mode 100644 tests/networkxml2xmlout/dnsmasq-options.xml diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index 2a6e3358fd..56937d6a4e 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -405,6 +405,17 @@ <zeroOrMore> <ref name="route"/> </zeroOrMore> + + <!-- <dnsmasq:options> --> + <optional> + <element name="options" ns="http://libvirt.org/schemas/network/dnsmasq/1.0"> + <zeroOrMore> + <element name="option"> + <attribute name='value'/> + </element> + </zeroOrMore> + </element> + </optional> </interleave> </element> </define> diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 1a4d6e7f7b..41fa89a4af 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -69,6 +69,8 @@ #include "virjson.h" #include "virnetworkportdef.h" +#include <libxml/xpathInternals.h> + #define VIR_FROM_THIS VIR_FROM_NETWORK #define MAX_BRIDGE_ID 256 @@ -83,6 +85,8 @@ VIR_LOG_INIT("network.bridge_driver"); +#define DNSMASQ_NAMESPACE_HREF "http://libvirt.org/schemas/network/dnsmasq/1.0" + static virNetworkDriverStatePtr network_driver; @@ -136,10 +140,126 @@ networkDnsmasqCapsRefresh(virNetworkDriverStatePtr driver) return 0; } -static virNetworkXMLOptionPtr + +static void +networkDnsmasqDefNamespaceFree(void *nsdata) +{ + networkDnsmasqXmlNsDefPtr def = nsdata; + if (!def) + return; + + virStringListFreeCount(def->options, def->noptions); + + VIR_FREE(def); +} + + +static int +networkDnsmasqDefNamespaceParseOptions(networkDnsmasqXmlNsDefPtr nsdef, + xmlXPathContextPtr ctxt) +{ + VIR_AUTOFREE(xmlNodePtr *) nodes = NULL; + ssize_t nnodes; + size_t i; + + if ((nnodes = virXPathNodeSet("./dnsmasq:options/dnsmasq:option", + ctxt, &nodes)) < 0) + return -1; + + if (nnodes == 0) + return 0; + + if (VIR_ALLOC_N(nsdef->options, nnodes) < 0) + return -1; + + for (i = 0; i < nnodes; i++) { + if (!(nsdef->options[nsdef->noptions++] = virXMLPropString(nodes[i], "value"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No dnsmasq options value specified")); + return -1; + } + } + + return 0; +} + + +static int +networkDnsmasqDefNamespaceParse(xmlXPathContextPtr ctxt, + void **data) +{ + networkDnsmasqXmlNsDefPtr nsdata = NULL; + int ret = -1; + + if (xmlXPathRegisterNs(ctxt, BAD_CAST "dnsmasq", + BAD_CAST DNSMASQ_NAMESPACE_HREF) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to register xml namespace '%s'"), + DNSMASQ_NAMESPACE_HREF); + return -1; + } + + if (VIR_ALLOC(nsdata) < 0) + return -1; + + if (networkDnsmasqDefNamespaceParseOptions(nsdata, ctxt)) + goto cleanup; + + if (nsdata->noptions > 0) + VIR_STEAL_PTR(*data, nsdata); + + ret = 0; + + cleanup: + networkDnsmasqDefNamespaceFree(nsdata); + return ret; +} + + +static int +networkDnsmasqDefNamespaceFormatXML(virBufferPtr buf, + void *nsdata) +{ + networkDnsmasqXmlNsDefPtr def = nsdata; + size_t i; + + if (!def->noptions) + return 0; + + virBufferAddLit(buf, "<dnsmasq:options>\n"); + virBufferAdjustIndent(buf, 2); + + for (i = 0; i < def->noptions; i++) { + virBufferEscapeString(buf, "<dnsmasq:option value='%s'/>\n", + def->options[i]); + } + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</dnsmasq:options>\n"); + + return 0; +} + + +static const char * +networkDnsmasqDefNamespaceHref(void) +{ + return "xmlns:dnsmasq='" DNSMASQ_NAMESPACE_HREF "'"; +} + + +virNetworkXMLNamespace networkDnsmasqXMLNamespace = { + .parse = networkDnsmasqDefNamespaceParse, + .free = networkDnsmasqDefNamespaceFree, + .format = networkDnsmasqDefNamespaceFormatXML, + .href = networkDnsmasqDefNamespaceHref, +}; + + +virNetworkXMLOptionPtr networkDnsmasqCreateXMLConf(void) { - return virNetworkXMLOptionNew(NULL); + return virNetworkXMLOptionNew(&networkDnsmasqXMLNamespace); } @@ -1480,6 +1600,12 @@ networkDnsmasqConfContents(virNetworkObjPtr obj, } } + if (def->namespaceData) { + networkDnsmasqXmlNsDefPtr dnsmasqxmlns = def->namespaceData; + for (i = 0; i < dnsmasqxmlns->noptions; i++) + virBufferAsprintf(&configbuf, "%s\n", dnsmasqxmlns->options[i]); + } + if (!(*configstr = virBufferContentAndReset(&configbuf))) goto cleanup; diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h index 7357c1754c..b095388a0b 100644 --- a/src/network/bridge_driver.h +++ b/src/network/bridge_driver.h @@ -27,6 +27,18 @@ #include "virdnsmasq.h" #include "virnetworkobj.h" +extern virNetworkXMLNamespace networkDnsmasqXMLNamespace; + +typedef struct _networkDnsmasqXmlNsDef networkDnsmasqXmlNsDef; +typedef networkDnsmasqXmlNsDef *networkDnsmasqXmlNsDefPtr; +struct _networkDnsmasqXmlNsDef { + size_t noptions; + char **options; +}; + +virNetworkXMLOptionPtr +networkDnsmasqCreateXMLConf(void); + int networkRegister(void); diff --git a/tests/Makefile.am b/tests/Makefile.am index 107f2de859..65192bac8e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -331,13 +331,13 @@ test_programs += virjsontest endif WITH_YAJL test_programs += \ - networkxml2xmltest \ networkxml2xmlupdatetest \ virnetworkportxml2xmltest \ $(NULL) if WITH_NETWORK test_programs += \ + networkxml2xmltest \ networkxml2conftest \ networkxml2firewalltest \ $(NULL) @@ -806,11 +806,6 @@ EXTRA_DIST += \ bhyveargv2xmlmock.c endif ! WITH_BHYVE -networkxml2xmltest_SOURCES = \ - networkxml2xmltest.c \ - testutils.c testutils.h -networkxml2xmltest_LDADD = $(LDADDS) - networkxml2xmlupdatetest_SOURCES = \ networkxml2xmlupdatetest.c \ testutils.c testutils.h @@ -822,6 +817,11 @@ virnetworkportxml2xmltest_SOURCES = \ virnetworkportxml2xmltest_LDADD = $(LDADDS) if WITH_NETWORK +networkxml2xmltest_SOURCES = \ + networkxml2xmltest.c \ + testutils.c testutils.h +networkxml2xmltest_LDADD = ../src/libvirt_driver_network_impl.la $(LDADDS) + networkxml2conftest_SOURCES = \ networkxml2conftest.c \ testutils.c testutils.h @@ -833,7 +833,7 @@ networkxml2firewalltest_SOURCES = \ networkxml2firewalltest_LDADD = ../src/libvirt_driver_network_impl.la $(LDADDS) else ! WITH_NETWORK -EXTRA_DIST += networkxml2conftest.c +EXTRA_DIST += networkxml2xmltest.c networkxml2conftest.c endif ! WITH_NETWORK if WITH_STORAGE_SHEEPDOG diff --git a/tests/networkxml2confdata/dnsmasq-options.conf b/tests/networkxml2confdata/dnsmasq-options.conf new file mode 100644 index 0000000000..867f355c79 --- /dev/null +++ b/tests/networkxml2confdata/dnsmasq-options.conf @@ -0,0 +1,18 @@ +##WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE +##OVERWRITTEN AND LOST. Changes to this configuration should be made using: +## virsh net-edit default +## or other application using the libvirt API. +## +## dnsmasq conf file created by libvirt +strict-order +except-interface=lo +bind-dynamic +interface=virbr0 +dhcp-range=192.168.122.2,192.168.122.254,255.255.255.0 +dhcp-no-override +dhcp-authoritative +dhcp-lease-max=253 +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts +foo=bar +cname=*.cloudapps.example.com,master.example.com diff --git a/tests/networkxml2confdata/dnsmasq-options.xml b/tests/networkxml2confdata/dnsmasq-options.xml new file mode 100644 index 0000000000..35a87b8e3e --- /dev/null +++ b/tests/networkxml2confdata/dnsmasq-options.xml @@ -0,0 +1,15 @@ +<network xmlns:dnsmasq="http://libvirt.org/schemas/network/dnsmasq/1.0"> + <name>default</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <bridge name="virbr0"/> + <forward mode="nat" dev="eth1"/> + <ip address="192.168.122.1" netmask="255.255.255.0"> + <dhcp> + <range start="192.168.122.2" end="192.168.122.254"/> + </dhcp> + </ip> + <dnsmasq:options> + <dnsmasq:option value="foo=bar"/> + <dnsmasq:option value="cname=*.cloudapps.example.com,master.example.com"/> + </dnsmasq:options> +</network> diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c index c445551099..dcb99aad6e 100644 --- a/tests/networkxml2conftest.c +++ b/tests/networkxml2conftest.c @@ -25,8 +25,12 @@ testCompareXMLToConfFiles(const char *inxml, const char *outconf, dnsmasqCapsPtr virCommandPtr cmd = NULL; char *pidfile = NULL; dnsmasqContext *dctx = NULL; + virNetworkXMLOptionPtr xmlopt = NULL; - if (!(def = virNetworkDefParseFile(inxml, NULL))) + if (!(xmlopt = networkDnsmasqCreateXMLConf())) + goto fail; + + if (!(def = virNetworkDefParseFile(inxml, xmlopt))) goto fail; if (!(obj = virNetworkObjNew())) @@ -63,6 +67,7 @@ testCompareXMLToConfFiles(const char *inxml, const char *outconf, dnsmasqCapsPtr VIR_FREE(actual); VIR_FREE(pidfile); virCommandFree(cmd); + virObjectUnref(xmlopt); virNetworkObjEndAPI(&obj); dnsmasqContextFree(dctx); return ret; @@ -141,6 +146,7 @@ mymain(void) DO_TEST("dhcp6-nat-network", dhcpv6); DO_TEST("dhcp6host-routed-network", dhcpv6); DO_TEST("ptr-domains-auto", dhcpv6); + DO_TEST("dnsmasq-options", dhcpv6); virObjectUnref(dhcpv6); virObjectUnref(full); diff --git a/tests/networkxml2xmlin/dnsmasq-options.xml b/tests/networkxml2xmlin/dnsmasq-options.xml new file mode 100644 index 0000000000..35a87b8e3e --- /dev/null +++ b/tests/networkxml2xmlin/dnsmasq-options.xml @@ -0,0 +1,15 @@ +<network xmlns:dnsmasq="http://libvirt.org/schemas/network/dnsmasq/1.0"> + <name>default</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <bridge name="virbr0"/> + <forward mode="nat" dev="eth1"/> + <ip address="192.168.122.1" netmask="255.255.255.0"> + <dhcp> + <range start="192.168.122.2" end="192.168.122.254"/> + </dhcp> + </ip> + <dnsmasq:options> + <dnsmasq:option value="foo=bar"/> + <dnsmasq:option value="cname=*.cloudapps.example.com,master.example.com"/> + </dnsmasq:options> +</network> diff --git a/tests/networkxml2xmlout/dnsmasq-options.xml b/tests/networkxml2xmlout/dnsmasq-options.xml new file mode 100644 index 0000000000..856a018f25 --- /dev/null +++ b/tests/networkxml2xmlout/dnsmasq-options.xml @@ -0,0 +1,17 @@ +<network xmlns:dnsmasq='http://libvirt.org/schemas/network/dnsmasq/1.0'> + <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'/> + <ip address='192.168.122.1' netmask='255.255.255.0'> + <dhcp> + <range start='192.168.122.2' end='192.168.122.254'/> + </dhcp> + </ip> + <dnsmasq:options> + <dnsmasq:option value='foo=bar'/> + <dnsmasq:option value='cname=*.cloudapps.example.com,master.example.com'/> + </dnsmasq:options> +</network> diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c index cd76ce5375..3d90023445 100644 --- a/tests/networkxml2xmltest.c +++ b/tests/networkxml2xmltest.c @@ -10,6 +10,7 @@ #include "network_conf.h" #include "testutilsqemu.h" #include "virstring.h" +#include "network/bridge_driver.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -29,15 +30,19 @@ testCompareXMLToXMLFiles(const char *inxml, const char *outxml, int ret; testCompareNetXML2XMLResult result = TEST_COMPARE_NET_XML2XML_RESULT_SUCCESS; virNetworkDefPtr dev = NULL; + virNetworkXMLOptionPtr xmlopt = NULL; - if (!(dev = virNetworkDefParseFile(inxml, NULL))) { + if (!(xmlopt = networkDnsmasqCreateXMLConf())) + goto cleanup; + + if (!(dev = virNetworkDefParseFile(inxml, xmlopt))) { result = TEST_COMPARE_NET_XML2XML_RESULT_FAIL_PARSE; goto cleanup; } if (expectResult == TEST_COMPARE_NET_XML2XML_RESULT_FAIL_PARSE) goto cleanup; - if (!(actual = virNetworkDefFormat(dev, NULL, flags))) { + if (!(actual = virNetworkDefFormat(dev, xmlopt, flags))) { result = TEST_COMPARE_NET_XML2XML_RESULT_FAIL_FORMAT; goto cleanup; } @@ -67,6 +72,7 @@ testCompareXMLToXMLFiles(const char *inxml, const char *outxml, VIR_FREE(actual); virNetworkDefFree(dev); + virObjectUnref(xmlopt); return ret; } @@ -158,6 +164,7 @@ mymain(void) DO_TEST_PARSE_ERROR("passthrough-duplicate"); DO_TEST("metadata"); DO_TEST("set-mtu"); + DO_TEST("dnsmasq-options"); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 2.21.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list