A typical XML representation of the virNWFilterBindingDefPtr struct looks like this: <filterbinding> <owner> <name>f25arm7</name> <uuid>12ac8b8c-4f23-4248-ae42-fdcd50c400fd</uuid> </owner> <portdev name='vnet1'/> <mac address='52:54:00:9d:81:b1'/> <filterref filter='clean-traffic'> <parameter name='MAC' value='52:54:00:9d:81:b1'/> </filterref> </filterbinding> Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> --- src/conf/virnwfilterbindingdef.c | 196 ++++++++++++++++++ src/conf/virnwfilterbindingdef.h | 18 ++ src/libvirt_private.syms | 5 + tests/Makefile.am | 7 + .../filter-vars.xml | 11 + .../virnwfilterbindingxml2xmldata/simple.xml | 9 + tests/virnwfilterbindingxml2xmltest.c | 113 ++++++++++ 7 files changed, 359 insertions(+) create mode 100644 tests/virnwfilterbindingxml2xmldata/filter-vars.xml create mode 100644 tests/virnwfilterbindingxml2xmldata/simple.xml create mode 100644 tests/virnwfilterbindingxml2xmltest.c diff --git a/src/conf/virnwfilterbindingdef.c b/src/conf/virnwfilterbindingdef.c index c7533d4063..23c040ab05 100644 --- a/src/conf/virnwfilterbindingdef.c +++ b/src/conf/virnwfilterbindingdef.c @@ -25,6 +25,7 @@ #include "virstring.h" #include "nwfilter_params.h" #include "virnwfilterbindingdef.h" +#include "viruuid.h" #define VIR_FROM_THIS VIR_FROM_NWFILTER @@ -81,3 +82,198 @@ virNWFilterBindingDefCopy(virNWFilterBindingDefPtr src) virNWFilterBindingDefFree(ret); return NULL; } + + +static virNWFilterBindingDefPtr +virNWFilterBindingDefParseXML(xmlXPathContextPtr ctxt) +{ + virNWFilterBindingDefPtr ret; + char *uuid = NULL; + char *mac = NULL; + xmlNodePtr node; + + if (VIR_ALLOC(ret) < 0) + return NULL; + + ret->portdevname = virXPathString("string(./portdev/@name)", ctxt); + if (!ret->portdevname) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("filter binding has no port dev name")); + goto cleanup; + } + + if (virXPathNode("./linkdev", ctxt)) { + ret->linkdevname = virXPathString("string(./linkdev/@name)", ctxt); + if (!ret->linkdevname) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("filter binding has no link dev name")); + goto cleanup; + } + } + + ret->ownername = virXPathString("string(./owner/name)", ctxt); + if (!ret->ownername) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("filter binding has no owner name")); + goto cleanup; + } + + uuid = virXPathString("string(./owner/uuid)", ctxt); + if (!uuid) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("filter binding has no owner UUID")); + goto cleanup; + } + + if (virUUIDParse(uuid, ret->owneruuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse UUID '%s'"), uuid); + VIR_FREE(uuid); + goto cleanup; + } + VIR_FREE(uuid); + + mac = virXPathString("string(./mac/@address)", ctxt); + if (!mac) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("filter binding has no MAC address")); + goto cleanup; + } + + if (virMacAddrParse(mac, &ret->mac) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to parse MAC '%s'"), mac); + VIR_FREE(mac); + goto cleanup; + } + VIR_FREE(mac); + + ret->filter = virXPathString("string(./filterref/@filter)", ctxt); + if (!ret->filter) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("filter binding has no filter reference")); + goto cleanup; + } + + node = virXPathNode("./filterref", ctxt); + if (node && + !(ret->filterparams = virNWFilterParseParamAttributes(node))) + goto cleanup; + + return ret; + + cleanup: + virNWFilterBindingDefFree(ret); + return NULL; +} + + +virNWFilterBindingDefPtr +virNWFilterBindingDefParseNode(xmlDocPtr xml, + xmlNodePtr root) +{ + xmlXPathContextPtr ctxt = NULL; + virNWFilterBindingDefPtr def = NULL; + + if (STRNEQ((const char *)root->name, "filterbinding")) { + virReportError(VIR_ERR_XML_ERROR, + "%s", + _("unknown root element for nwfilter binding")); + goto cleanup; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virReportOOMError(); + goto cleanup; + } + + ctxt->node = root; + def = virNWFilterBindingDefParseXML(ctxt); + + cleanup: + xmlXPathFreeContext(ctxt); + return def; +} + + +static virNWFilterBindingDefPtr +virNWFilterBindingDefParse(const char *xmlStr, + const char *filename) +{ + virNWFilterBindingDefPtr def = NULL; + xmlDocPtr xml; + + if ((xml = virXMLParse(filename, xmlStr, _("(nwfilterbinding_definition)")))) { + def = virNWFilterBindingDefParseNode(xml, xmlDocGetRootElement(xml)); + xmlFreeDoc(xml); + } + + return def; +} + + +virNWFilterBindingDefPtr +virNWFilterBindingDefParseString(const char *xmlStr) +{ + return virNWFilterBindingDefParse(xmlStr, NULL); +} + + +virNWFilterBindingDefPtr +virNWFilterBindingDefParseFile(const char *filename) +{ + return virNWFilterBindingDefParse(NULL, filename); +} + +char * +virNWFilterBindingDefFormat(const virNWFilterBindingDef *def) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (virNWFilterBindingDefFormatBuf(&buf, def) < 0) { + virBufferFreeAndReset(&buf); + return NULL; + } + + if (virBufferCheckError(&buf) < 0) + return NULL; + + return virBufferContentAndReset(&buf); +} + + +int +virNWFilterBindingDefFormatBuf(virBufferPtr buf, + const virNWFilterBindingDef *def) +{ + char uuid[VIR_UUID_STRING_BUFLEN]; + char mac[VIR_MAC_STRING_BUFLEN]; + + virBufferAddLit(buf, "<filterbinding>\n"); + + virBufferAdjustIndent(buf, 2); + + virBufferAddLit(buf, "<owner>\n"); + virBufferAdjustIndent(buf, 2); + virBufferEscapeString(buf, "<name>%s</name>\n", def->ownername); + virUUIDFormat(def->owneruuid, uuid); + virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuid); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</owner>\n"); + + virBufferEscapeString(buf, "<portdev name='%s'/>\n", def->portdevname); + if (def->linkdevname) + virBufferEscapeString(buf, "<linkdev name='%s'/>\n", def->linkdevname); + + virMacAddrFormat(&def->mac, mac); + virBufferAsprintf(buf, "<mac address='%s'/>\n", mac); + + if (virNWFilterFormatParamAttributes(buf, def->filterparams, def->filter) < 0) + return -1; + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</filterbinding>\n"); + + return 0; +} diff --git a/src/conf/virnwfilterbindingdef.h b/src/conf/virnwfilterbindingdef.h index e3b18af151..af7fab6064 100644 --- a/src/conf/virnwfilterbindingdef.h +++ b/src/conf/virnwfilterbindingdef.h @@ -24,6 +24,7 @@ # include "internal.h" # include "virmacaddr.h" # include "virhash.h" +# include "virbuffer.h" typedef struct _virNWFilterBindingDef virNWFilterBindingDef; typedef virNWFilterBindingDef *virNWFilterBindingDefPtr; @@ -44,4 +45,21 @@ virNWFilterBindingDefFree(virNWFilterBindingDefPtr binding); virNWFilterBindingDefPtr virNWFilterBindingDefCopy(virNWFilterBindingDefPtr src); +virNWFilterBindingDefPtr +virNWFilterBindingDefParseNode(xmlDocPtr xml, + xmlNodePtr root); + +virNWFilterBindingDefPtr +virNWFilterBindingDefParseString(const char *xml); + +virNWFilterBindingDefPtr +virNWFilterBindingDefParseFile(const char *filename); + +char * +virNWFilterBindingDefFormat(const virNWFilterBindingDef *def); + +int +virNWFilterBindingDefFormatBuf(virBufferPtr buf, + const virNWFilterBindingDef *def); + #endif /* VIR_NWFILTER_BINDING_DEF_H */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index fb754fbfea..03145c70d5 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1043,7 +1043,12 @@ virNodeDeviceObjListRemove; # conf/virnwfilterbindingdef.h virNWFilterBindingDefCopy; +virNWFilterBindingDefFormat; +virNWFilterBindingDefFormatBuf; virNWFilterBindingDefFree; +virNWFilterBindingDefParseFile; +virNWFilterBindingDefParseNode; +virNWFilterBindingDefParseString; # conf/virnwfilterobj.h diff --git a/tests/Makefile.am b/tests/Makefile.am index 621480dd0c..036335e770 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -156,6 +156,7 @@ EXTRA_DIST = \ virmock.h \ virnetdaemondata \ virnetdevtestdata \ + virnwfilterbindingxml2xmldata \ virpcitestdata \ virscsidata \ virsh-uriprecedence \ @@ -352,6 +353,7 @@ test_programs += storagebackendsheepdogtest endif WITH_STORAGE_SHEEPDOG test_programs += nwfilterxml2xmltest +test_programs += virnwfilterbindingxml2xmltest if WITH_NWFILTER test_programs += nwfilterebiptablestest @@ -855,6 +857,11 @@ nwfilterxml2xmltest_SOURCES = \ testutils.c testutils.h nwfilterxml2xmltest_LDADD = $(LDADDS) +virnwfilterbindingxml2xmltest_SOURCES = \ + virnwfilterbindingxml2xmltest.c \ + testutils.c testutils.h +virnwfilterbindingxml2xmltest_LDADD = $(LDADDS) + if WITH_NWFILTER nwfilterebiptablestest_SOURCES = \ nwfilterebiptablestest.c \ diff --git a/tests/virnwfilterbindingxml2xmldata/filter-vars.xml b/tests/virnwfilterbindingxml2xmldata/filter-vars.xml new file mode 100644 index 0000000000..dcff9640ce --- /dev/null +++ b/tests/virnwfilterbindingxml2xmldata/filter-vars.xml @@ -0,0 +1,11 @@ +<filterbinding> + <owner> + <name>memtest</name> + <uuid>d54df46f-1ab5-4a22-8618-4560ef5fac2c</uuid> + </owner> + <portdev name='vnet0'/> + <mac address='52:54:00:7b:35:93'/> + <filterref filter='clean-traffic'> + <parameter name='MAC' value='52:54:00:7b:35:93'/> + </filterref> +</filterbinding> diff --git a/tests/virnwfilterbindingxml2xmldata/simple.xml b/tests/virnwfilterbindingxml2xmldata/simple.xml new file mode 100644 index 0000000000..4577729a3c --- /dev/null +++ b/tests/virnwfilterbindingxml2xmldata/simple.xml @@ -0,0 +1,9 @@ +<filterbinding> + <owner> + <name>memtest</name> + <uuid>d54df46f-1ab5-4a22-8618-4560ef5fac2c</uuid> + </owner> + <portdev name='vnet0'/> + <mac address='52:54:00:7b:35:93'/> + <filterref filter='clean-traffic'/> +</filterbinding> diff --git a/tests/virnwfilterbindingxml2xmltest.c b/tests/virnwfilterbindingxml2xmltest.c new file mode 100644 index 0000000000..96edbdcf59 --- /dev/null +++ b/tests/virnwfilterbindingxml2xmltest.c @@ -0,0 +1,113 @@ +/* + * virnwfilterbindingxml2xmltest.h: network filter binding XML testing + * + * Copyright (C) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <sys/types.h> +#include <fcntl.h> + +#include "internal.h" +#include "testutils.h" +#include "virxml.h" +#include "virnwfilterbindingdef.h" +#include "testutilsqemu.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +static int +testCompareXMLToXMLFiles(const char *xml) +{ + char *actual = NULL; + int ret = -1; + virNWFilterBindingDefPtr dev = NULL; + + virResetLastError(); + + if (!(dev = virNWFilterBindingDefParseFile(xml))) { + goto fail; + } + + if (!(actual = virNWFilterBindingDefFormat(dev))) + goto fail; + + if (virTestCompareToFile(actual, xml) < 0) + goto fail; + + ret = 0; + + fail: + VIR_FREE(actual); + virNWFilterBindingDefFree(dev); + return ret; +} + +typedef struct test_parms { + const char *name; +} test_parms; + +static int +testCompareXMLToXMLHelper(const void *data) +{ + int result = -1; + const test_parms *tp = data; + char *xml = NULL; + + if (virAsprintf(&xml, "%s/virnwfilterbindingxml2xmldata/%s.xml", + abs_srcdir, tp->name) < 0) { + goto cleanup; + } + + result = testCompareXMLToXMLFiles(xml); + + cleanup: + VIR_FREE(xml); + + return result; +} + +static int +mymain(void) +{ + int ret = 0; + +#define DO_TEST(NAME) \ + do { \ + test_parms tp = { \ + .name = NAME, \ + }; \ + if (virTestRun("NWFilter XML-2-XML " NAME, \ + testCompareXMLToXMLHelper, (&tp)) < 0) \ + ret = -1; \ + } while (0) + + DO_TEST("simple"); + DO_TEST("filter-vars"); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIR_TEST_MAIN(mymain) -- 2.17.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list