[libvirt] [PATCH v3 13/36] conf: introduce virNetworkPortDefPtr struct and XML support

Laine Stump laine at laine.org
Fri Mar 22 15:28:17 UTC 2019


On 3/19/19 8:46 AM, Daniel P. Berrangé wrote:
> Introduce a virNetworkPortDefPtr struct to represent the data associated
> with a virtual network port. Add APIs for parsing/formatting XML docs
> with the data.
>
> Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
> ---
>   src/conf/Makefile.inc.am                      |   2 +
>   src/conf/virnetworkportdef.c                  | 514 ++++++++++++++++++
>   src/conf/virnetworkportdef.h                  | 112 ++++
>   src/libvirt_private.syms                      |  10 +
>   tests/Makefile.am                             |   7 +
>   .../plug-bridge-mactbl.xml                    |   9 +
>   .../virnetworkportxml2xmldata/plug-bridge.xml |  12 +
>   .../virnetworkportxml2xmldata/plug-direct.xml |  12 +
>   .../plug-hostdev-pci.xml                      |  12 +
>   tests/virnetworkportxml2xmldata/plug-none.xml |   8 +
>   tests/virnetworkportxml2xmltest.c             | 104 ++++
>   11 files changed, 802 insertions(+)
>   create mode 100644 src/conf/virnetworkportdef.c
>   create mode 100644 src/conf/virnetworkportdef.h
>   create mode 100644 tests/virnetworkportxml2xmldata/plug-bridge-mactbl.xml
>   create mode 100644 tests/virnetworkportxml2xmldata/plug-bridge.xml
>   create mode 100644 tests/virnetworkportxml2xmldata/plug-direct.xml
>   create mode 100644 tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml
>   create mode 100644 tests/virnetworkportxml2xmldata/plug-none.xml
>   create mode 100644 tests/virnetworkportxml2xmltest.c
>
> diff --git a/src/conf/Makefile.inc.am b/src/conf/Makefile.inc.am
> index 9b4d80485b..388917c5dd 100644
> --- a/src/conf/Makefile.inc.am
> +++ b/src/conf/Makefile.inc.am
> @@ -5,6 +5,8 @@ NETDEV_CONF_SOURCES = \
>   	conf/netdev_vport_profile_conf.c \
>   	conf/netdev_vlan_conf.h \
>   	conf/netdev_vlan_conf.c \
> +	conf/virnetworkportdef.h \
> +	conf/virnetworkportdef.c \
>   	$(NULL)
>   
>   DOMAIN_CONF_SOURCES = \
> diff --git a/src/conf/virnetworkportdef.c b/src/conf/virnetworkportdef.c
> new file mode 100644
> index 0000000000..7023d9607e
> --- /dev/null
> +++ b/src/conf/virnetworkportdef.c
> @@ -0,0 +1,514 @@
> +/*
> + * virnetworkportdef.c: network port XML processing
> + *
> + * 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 "viralloc.h"
> +#include "virerror.h"
> +#include "virstring.h"
> +#include "virfile.h"
> +#include "virnetworkportdef.h"
> +#include "network_conf.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_NETWORK
> +
> +VIR_ENUM_IMPL(virNetworkPortPlug, VIR_NETWORK_PORT_PLUG_TYPE_LAST,
> +              "none", "bridge", "direct", "hostdev-pci");


Are we going to need to differentiate between veth and macvtap later? 
Having the choice implied based on which hypervisor it's coming from 
seems potentially troublesome...


> +
> +void
> +virNetworkPortDefFree(virNetworkPortDefPtr def)
> +{
> +    if (!def)
> +        return;
> +
> +    VIR_FREE(def->ownername);
> +    VIR_FREE(def->group);
> +
> +    virNetDevBandwidthFree(def->bandwidth);
> +    virNetDevVlanClear(&def->vlan);
> +    VIR_FREE(def->virtPortProfile);
> +
> +    switch ((virNetworkPortPlugType)def->plugtype) {
> +    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
> +        break;
> +
> +    case VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE:
> +        VIR_FREE(def->plug.bridge.brname);
> +        break;
> +
> +    case VIR_NETWORK_PORT_PLUG_TYPE_DIRECT:
> +        VIR_FREE(def->plug.direct.linkdev);
> +        break;
> +
> +    case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:
> +        break;
> +
> +    case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
> +    default:
> +        break;
> +    }
> +
> +    VIR_FREE(def);
> +}
> +
> +
> +
> +static virNetworkPortDefPtr
> +virNetworkPortDefParseXML(xmlXPathContextPtr ctxt)
> +{
> +    virNetworkPortDefPtr def;
> +    char *uuid = NULL;
> +    xmlNodePtr virtPortNode;
> +    xmlNodePtr vlanNode;
> +    xmlNodePtr bandwidthNode;
> +    xmlNodePtr addressNode;
> +    char *trustGuestRxFilters = NULL;
> +    char *mac = NULL;
> +    char *macmgr = NULL;
> +    char *mode = NULL;
> +    char *plugtype = NULL;
> +    char *managed = NULL;
> +    char *driver = NULL;
> +    char *class_id = NULL;


Maybe you could make all of those VIR_AUTOFREE() to further the world 
conquest of that stuff. (I still haven't decided if I'm really a fan of 
it, but it does seem to be taking over the source).


There's one or two comments below this, but only for comic relief, 
nothing of substance.


Reviewed-by: Laine Stump <laine at laine.org>


(I'm assuming the XML documentation is in a followup patch somewhere?)


> +
> +    if (VIR_ALLOC(def) < 0)
> +        return NULL;
> +
> +    uuid = virXPathString("string(./uuid)", ctxt);
> +    if (!uuid) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       "%s", _("network port has no uuid"));
> +        goto error;
> +    }
> +    if (virUUIDParse(uuid, def->uuid) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Unable to parse UUID '%s'"), uuid);
> +        goto error;
> +    }
> +
> +    def->ownername = virXPathString("string(./owner/name)", ctxt);
> +    if (!def->ownername) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       "%s", _("network port has no owner name"));
> +        goto error;
> +    }
> +
> +    VIR_FREE(uuid);
> +    uuid = virXPathString("string(./owner/uuid)", ctxt);
> +    if (!uuid) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       "%s", _("network port has no owner UUID"));
> +        goto error;
> +    }
> +
> +    if (virUUIDParse(uuid, def->owneruuid) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Unable to parse UUID '%s'"), uuid);
> +        goto error;
> +    }
> +
> +    def->group = virXPathString("string(./group)", ctxt);
> +
> +    virtPortNode = virXPathNode("./virtualport", ctxt);
> +    if (virtPortNode &&
> +        (!(def->virtPortProfile = virNetDevVPortProfileParse(virtPortNode, 0)))) {
> +        goto error;
> +    }
> +
> +    mac = virXPathString("string(./mac/@address)", ctxt);
> +    if (!mac) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       "%s", _("network port has no mac"));
> +        goto error;
> +    }
> +    if (virMacAddrParse(mac, &def->mac) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Unable to parse MAC '%s'"), mac);
> +        goto error;
> +    }
> +
> +    class_id = virXPathString("string(./class/@id)", ctxt);


Good, so the class_id issue we've talked about in other patches no 
longer exists once we're using NetworkPortDef instead of ActualNetDef.


> +    if (class_id &&
> +        virStrToLong_ui(class_id, NULL, 10, &def->class_id) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Unable to parse class id '%s'"),
> +                       class_id);
> +        goto error;
> +    }
> +
> +    bandwidthNode = virXPathNode("./bandwidth", ctxt);
> +    /*
> +     * We don't know if the port will allow the "floor" param or
> +     * not at this stage, so we must just tell virNetDevBandwidthParse
> +     * to allow it regardless. Any bad config must be reported at
> +     * time of use instead.
> +     */
> +    if (bandwidthNode &&
> +        virNetDevBandwidthParse(&def->bandwidth, bandwidthNode, true) < 0)
> +        goto error;
> +
> +    vlanNode = virXPathNode("./vlan", ctxt);
> +    if (vlanNode && virNetDevVlanParse(vlanNode, ctxt, &def->vlan) < 0)
> +        goto error;
> +
> +
> +    trustGuestRxFilters
> +        = virXPathString("string(./rxfilters/@trustGuest)", ctxt);
> +    if (trustGuestRxFilters) {
> +        if ((def->trustGuestRxFilters
> +             = virTristateBoolTypeFromString(trustGuestRxFilters)) <= 0) {
> +            virReportError(VIR_ERR_XML_ERROR,
> +                           _("Invalid guest rx filters trust setting '%s' "),
> +                           trustGuestRxFilters);
> +            goto error;
> +        }
> +    }
> +
> +    plugtype = virXPathString("string(./plug/@type)", ctxt);
> +
> +    if (plugtype &&
> +        (def->plugtype = virNetworkPortPlugTypeFromString(plugtype)) < 0) {
> +        virReportError(VIR_ERR_XML_ERROR,
> +                       _("Invalid network prt plug type '%s'"), plugtype);
> +    }
> +
> +    switch (def->plugtype) {
> +    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
> +        break;
> +
> +    case VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE:
> +        if (!(def->plug.bridge.brname = virXPathString("string(./plug/@bridge)", ctxt))) {
> +            virReportError(VIR_ERR_XML_ERROR, "%s",
> +                           _("Missing network port bridge name"));
> +            goto error;
> +        }
> +        macmgr = virXPathString("string(./plug/@macTableManager)", ctxt);
> +        if (macmgr &&
> +            (def->plug.bridge.macTableManager =
> +             virNetworkBridgeMACTableManagerTypeFromString(macmgr)) <= 0) {
> +            virReportError(VIR_ERR_XML_ERROR,
> +                           _("Invalid macTableManager setting '%s' "
> +                             "in network port"), macmgr);
> +            goto error;
> +        }
> +        break;
> +
> +    case VIR_NETWORK_PORT_PLUG_TYPE_DIRECT:
> +        if (!(def->plug.direct.linkdev = virXPathString("string(./plug/@dev)", ctxt))) {
> +            virReportError(VIR_ERR_XML_ERROR, "%s",
> +                           _("Missing network port link device name"));
> +            goto error;
> +        }
> +        mode = virXPathString("string(./plug/@mode)", ctxt);
> +        if (mode &&
> +            (def->plug.direct.mode =
> +             virNetDevMacVLanModeTypeFromString(mode)) < 0) {
> +            virReportError(VIR_ERR_XML_ERROR,
> +                           _("Invalid mode setting '%s' in network port"), mode);
> +            goto error;
> +        }
> +        break;
> +
> +    case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:
> +        managed = virXPathString("string(./plug/@managed)", ctxt);
> +        if (managed &&
> +            (def->plug.hostdevpci.managed =
> +             virTristateBoolTypeFromString(managed)) < 0) {
> +            virReportError(VIR_ERR_XML_ERROR,
> +                           _("Invalid managed setting '%s' in network port"), mode);
> +            goto error;
> +        }
> +        driver = virXPathString("string(./plug/driver/@name)", ctxt);
> +        if (driver &&
> +            (def->plug.hostdevpci.driver =
> +             virNetworkForwardDriverNameTypeFromString(driver)) <= 0) {
> +              virReportError(VIR_ERR_XML_ERROR, "%s",
> +                           _("Missing network port driver name"));
> +            goto error;
> +        }
> +        if (!(addressNode = virXPathNode("./plug/address", ctxt))) {
> +            virReportError(VIR_ERR_XML_ERROR, "%s",
> +                           _("Missing network port PCI address"));
> +            goto error;
> +        }
> +
> +        if (virPCIDeviceAddressParseXML(addressNode, &def->plug.hostdevpci.addr) < 0)
> +            goto error;
> +        break;
> +
> +    case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
> +    default:
> +        virReportEnumRangeError(virNetworkPortPlugType, def->plugtype);
> +        goto error;
> +    }
> +
> + cleanup:
> +    VIR_FREE(class_id);
> +    VIR_FREE(uuid);
> +    VIR_FREE(plugtype);
> +    VIR_FREE(mac);
> +    VIR_FREE(mode);
> +    VIR_FREE(macmgr);
> +    VIR_FREE(driver);
> +    VIR_FREE(managed);
> +    return def;
> +
> + error:
> +    virNetworkPortDefFree(def);
> +    def = NULL;
> +    goto cleanup;
> +}
> +
> +
> +virNetworkPortDefPtr
> +virNetworkPortDefParseNode(xmlDocPtr xml,
> +                           xmlNodePtr root)
> +{
> +    xmlXPathContextPtr ctxt = NULL;
> +    virNetworkPortDefPtr def = NULL;
> +
> +    if (STRNEQ((const char *)root->name, "networkport")) {
> +        virReportError(VIR_ERR_XML_ERROR,
> +                       "%s",
> +                       _("unknown root element for network port"));
> +        goto cleanup;
> +    }
> +
> +    ctxt = xmlXPathNewContext(xml);
> +    if (ctxt == NULL) {
> +        virReportOOMError();
> +        goto cleanup;
> +    }
> +
> +    ctxt->node = root;
> +    def = virNetworkPortDefParseXML(ctxt);
> +
> + cleanup:
> +    xmlXPathFreeContext(ctxt);
> +    return def;
> +}
> +
> +
> +static virNetworkPortDefPtr
> +virNetworkPortDefParse(const char *xmlStr,
> +                       const char *filename)
> +{
> +    virNetworkPortDefPtr def = NULL;
> +    xmlDocPtr xml;
> +
> +    if ((xml = virXMLParse(filename, xmlStr, _("(networkport_definition)")))) {
> +        def = virNetworkPortDefParseNode(xml, xmlDocGetRootElement(xml));
> +        xmlFreeDoc(xml);
> +    }
> +
> +    return def;
> +}
> +
> +
> +virNetworkPortDefPtr
> +virNetworkPortDefParseString(const char *xmlStr)
> +{
> +    return virNetworkPortDefParse(xmlStr, NULL);
> +}
> +
> +
> +virNetworkPortDefPtr
> +virNetworkPortDefParseFile(const char *filename)
> +{
> +    return virNetworkPortDefParse(NULL, filename);
> +}
> +
> +
> +char *
> +virNetworkPortDefFormat(const virNetworkPortDef *def)
> +{
> +    virBuffer buf = VIR_BUFFER_INITIALIZER;
> +
> +    if (virNetworkPortDefFormatBuf(&buf, def) < 0) {
> +        virBufferFreeAndReset(&buf);
> +        return NULL;
> +    }
> +
> +    if (virBufferCheckError(&buf) < 0)
> +        return NULL;
> +
> +    return virBufferContentAndReset(&buf);
> +}
> +
> +
> +int
> +virNetworkPortDefFormatBuf(virBufferPtr buf,
> +                           const virNetworkPortDef *def)
> +{
> +    char uuid[VIR_UUID_STRING_BUFLEN];
> +    char macaddr[VIR_MAC_STRING_BUFLEN];
> +
> +    virBufferAddLit(buf, "<networkport>\n");
> +
> +    virBufferAdjustIndent(buf, 2);
> +
> +    virUUIDFormat(def->uuid, uuid);
> +    virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuid);
> +
> +    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");
> +
> +    if (def->group)
> +        virBufferEscapeString(buf, "<group>%s</group>\n", def->group);
> +
> +    virMacAddrFormat(&def->mac, macaddr);
> +    virBufferAsprintf(buf, "<mac address='%s'/>\n", macaddr);
> +
> +    if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
> +        return -1;
> +    virNetDevBandwidthFormat(def->bandwidth, buf);
> +    if (def->class_id)
> +        virBufferAsprintf(buf, "<class id='%u'/>\n", def->class_id);
> +    if (virNetDevVlanFormat(&def->vlan, buf) < 0)
> +        return -1;
> +    if (def->trustGuestRxFilters)
> +        virBufferAsprintf(buf, "<rxfilters trustGuest='%s'/>\n",
> +                          virTristateBoolTypeToString(def->trustGuestRxFilters));
> +
> +    if (def->plugtype != VIR_NETWORK_PORT_PLUG_TYPE_NONE) {
> +        virBufferAsprintf(buf, "<plug type='%s'",
> +                          virNetworkPortPlugTypeToString(def->plugtype));
> +
> +        switch (def->plugtype) {
> +        case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
> +            break;
> +
> +        case VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE:
> +            virBufferEscapeString(buf, " bridge='%s'", def->plug.bridge.brname);
> +            if (def->plug.bridge.macTableManager)
> +                virBufferAsprintf(buf, " macTableManager='%s'",
> +                                  virNetworkBridgeMACTableManagerTypeToString(
> +                                      def->plug.bridge.macTableManager));
> +            virBufferAddLit(buf, "/>\n");
> +            break;
> +
> +        case VIR_NETWORK_PORT_PLUG_TYPE_DIRECT:
> +            virBufferEscapeString(buf, " dev='%s'", def->plug.direct.linkdev);
> +            virBufferAsprintf(buf, " mode='%s'",
> +                              virNetDevMacVLanModeTypeToString(
> +                                  def->plug.direct.mode));
> +            virBufferAddLit(buf, "/>\n");
> +            break;
> +
> +        case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:
> +            virBufferAsprintf(buf, " managed='%s'>\n",
> +                              def->plug.hostdevpci.managed ? "yes" : "no");
> +            virBufferAdjustIndent(buf, 2);
> +            if (def->plug.hostdevpci.driver)
> +                virBufferEscapeString(buf, "<driver name='%s'/>\n",
> +                                      virNetworkForwardDriverNameTypeToString(
> +                                          def->plug.hostdevpci.driver));
> +
> +            virPCIDeviceAddressFormat(buf, def->plug.hostdevpci.addr, false);
> +            virBufferAdjustIndent(buf, -2);
> +            virBufferAddLit(buf, "</plug>\n");
> +            break;
> +
> +        case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
> +        default:
> +            virReportEnumRangeError(virNetworkPortPlugType, def->plugtype);
> +            return -1;
> +        }
> +    }
> +
> +
> +    virBufferAdjustIndent(buf, -2);
> +    virBufferAddLit(buf, "</networkport>\n");
> +
> +    return 0;
> +}
> +
> +
> +static char *
> +virNetworkPortDefConfigFile(const char *dir,
> +                            const char *name)
> +{
> +    char *ret = NULL;
> +
> +    ignore_value(virAsprintf(&ret, "%s/%s.xml", dir, name));
> +    return ret;
> +}
> +
> +
> +int
> +virNetworkPortDefSaveStatus(virNetworkPortDef *def,
> +                            const char *dir)
> +{
> +    char uuidstr[VIR_UUID_STRING_BUFLEN];
> +    char *path;
> +    char *xml = NULL;
> +    int ret = -1;
> +
> +    virUUIDFormat(def->uuid, uuidstr);
> +
> +    if (virFileMakePath(dir) < 0)
> +        goto cleanup;
> +
> +    if (!(path = virNetworkPortDefConfigFile(dir, uuidstr)))
> +        goto cleanup;
> +
> +    if (!(xml = virNetworkPortDefFormat(def)))
> +        goto cleanup;
> +
> +    if (virXMLSaveFile(path, uuidstr, "net-port-create", xml) < 0)
> +        goto cleanup;
> +
> +    ret = 0;
> + cleanup:
> +    VIR_FREE(xml);
> +    VIR_FREE(path);
> +    return ret;
> +}
> +
> +
> +int
> +virNetworkPortDefDeleteStatus(virNetworkPortDef *def,
> +                              const char *dir)
> +{
> +    char uuidstr[VIR_UUID_STRING_BUFLEN];
> +    char *path;
> +    int ret = -1;
> +
> +    virUUIDFormat(def->uuid, uuidstr);
> +
> +    if (!(path = virNetworkPortDefConfigFile(dir, uuidstr)))
> +        goto cleanup;
> +
> +    if (unlink(path) < 0 && errno != ENOENT) {
> +        virReportSystemError(errno,
> +                             _("Unable to delete %s"), path);
> +        goto cleanup;
> +    }
> +
> +    ret = 0;
> + cleanup:
> +    VIR_FREE(path);
> +    return ret;
> +}
> diff --git a/src/conf/virnetworkportdef.h b/src/conf/virnetworkportdef.h
> new file mode 100644
> index 0000000000..3897013a86
> --- /dev/null
> +++ b/src/conf/virnetworkportdef.h
> @@ -0,0 +1,112 @@
> +/*
> + * virnetworkportdef.h: network port XML processing
> + *
> + * 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/>.
> + *
> + */
> +
> +#ifndef LIBVIRT_VIRNETWORKPORTDEF_H
> +# define LIBVIRT_VIRNETWORKPORTDEF_H
> +
> +# include "internal.h"
> +# include "viruuid.h"
> +# include "virnetdevvlan.h"
> +# include "virnetdevvportprofile.h"
> +# include "virnetdevbandwidth.h"
> +# include "virpci.h"
> +# include "virxml.h"
> +# include "netdev_vport_profile_conf.h"
> +# include "netdev_bandwidth_conf.h"
> +# include "netdev_vlan_conf.h"
> +
> +typedef struct _virNetworkPortDef virNetworkPortDef;
> +typedef virNetworkPortDef *virNetworkPortDefPtr;
> +
> +typedef enum {
> +    VIR_NETWORK_PORT_PLUG_TYPE_NONE,
> +    VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE,
> +    VIR_NETWORK_PORT_PLUG_TYPE_DIRECT,
> +    VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI,
> +
> +    VIR_NETWORK_PORT_PLUG_TYPE_LAST,
> +} virNetworkPortPlugType;
> +
> +VIR_ENUM_DECL(virNetworkPortPlug);
> +
> +struct _virNetworkPortDef {
> +    unsigned char uuid[VIR_UUID_BUFLEN];
> +    char *ownername;
> +    unsigned char owneruuid[VIR_UUID_BUFLEN];
> +
> +    char *group;
> +    virMacAddr mac;
> +
> +    virNetDevVPortProfilePtr virtPortProfile;
> +    virNetDevBandwidthPtr bandwidth;
> +    unsigned int class_id; /* class ID for bandwidth 'floor' */
> +    virNetDevVlan vlan;
> +    int trustGuestRxFilters; /* enum virTristateBool */
> +
> +    int plugtype; /* virNetworkPortPlugType */
> +    union {
> +        struct {
> +            char *brname;
> +            int macTableManager; /* enum virNetworkBridgeMACTableManagerType */
> +        } bridge;
> +        struct {
> +            char *linkdev;
> +            int mode; /* enum virMacvtapMode from util/macvtap.h */
> +        } direct;
> +        struct {
> +            virPCIDeviceAddress addr; /* PCI Address of device */
> +            int driver; /* virNetworkForwardDriverNameType */


(Aside: someday we should get rid of all the stuff that's there only to 
allow legacy qemu PCI device assignment, since we no longer support any 
distros that actually have it built into the kernel. I'm pretty sure 
that's the only reason for the "driver" attribute...)


> +            int managed;
> +        } hostdevpci;
> +    } plug;
> +};
> +
> +
> +void
> +virNetworkPortDefFree(virNetworkPortDefPtr port);
> +
> +virNetworkPortDefPtr
> +virNetworkPortDefParseNode(xmlDocPtr xml,
> +                           xmlNodePtr root);
> +
> +virNetworkPortDefPtr
> +virNetworkPortDefParseString(const char *xml);
> +
> +virNetworkPortDefPtr
> +virNetworkPortDefParseFile(const char *filename);
> +
> +char *
> +virNetworkPortDefFormat(const virNetworkPortDef *def);
> +
> +int
> +virNetworkPortDefFormatBuf(virBufferPtr buf,
> +                           const virNetworkPortDef *def);
> +
> +int
> +virNetworkPortDefSaveStatus(virNetworkPortDef *def,
> +                            const char *dir);
> +
> +int
> +virNetworkPortDefDeleteStatus(virNetworkPortDef *def,
> +                              const char *dir);
> +
> +
> +#endif /* LIBVIRT_VIRNETWORKPORTDEF_H */
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 6f5a734fdb..0694db7089 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -1061,6 +1061,16 @@ virNetworkObjUpdate;
>   virNetworkObjUpdateAssignDef;
>   
>   
> +# conf/virnetworkportdef.h
> +virNetworkPortDefFormat;
> +virNetworkPortDefFormatBuf;
> +virNetworkPortDefFree;
> +virNetworkPortDefParseFile;
> +virNetworkPortDefParseNode;
> +virNetworkPortDefParseString;
> +virNetworkPortDefSaveStatus;
> +
> +
>   # conf/virnodedeviceobj.h
>   virNodeDeviceObjEndAPI;
>   virNodeDeviceObjGetDef;
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index 29f1fe2d2a..e39e3658a3 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -148,6 +148,7 @@ EXTRA_DIST = \
>   	virmock.h \
>   	virnetdaemondata \
>   	virnetdevtestdata \
> +	virnetworkportxml2xmldata \
>   	virnwfilterbindingxml2xmldata \
>   	virpcitestdata \
>   	virscsidata \
> @@ -334,6 +335,7 @@ endif WITH_YAJL
>   test_programs += \
>   		networkxml2xmltest \
>   		networkxml2xmlupdatetest \
> +		virnetworkportxml2xmltest \
>   		$(NULL)
>   
>   if WITH_NETWORK
> @@ -830,6 +832,11 @@ networkxml2xmlupdatetest_SOURCES = \
>   	testutils.c testutils.h
>   networkxml2xmlupdatetest_LDADD = $(LDADDS)
>   
> +virnetworkportxml2xmltest_SOURCES = \
> +	virnetworkportxml2xmltest.c \
> +	testutils.c testutils.h
> +virnetworkportxml2xmltest_LDADD = $(LDADDS)
> +
>   if WITH_NETWORK
>   networkxml2conftest_SOURCES = \
>   	networkxml2conftest.c \
> diff --git a/tests/virnetworkportxml2xmldata/plug-bridge-mactbl.xml b/tests/virnetworkportxml2xmldata/plug-bridge-mactbl.xml
> new file mode 100644
> index 0000000000..8036bc2e1c
> --- /dev/null
> +++ b/tests/virnetworkportxml2xmldata/plug-bridge-mactbl.xml
> @@ -0,0 +1,9 @@
> +<networkport>
> +  <uuid>5d744f21-ba4a-4d6e-bdb2-30a35ff3207d</uuid>
> +  <owner>
> +    <name>memtest</name>
> +    <uuid>d54df46f-1ab5-4a22-8618-4560ef5fac2c</uuid>
> +  </owner>
> +  <mac address='52:54:00:7b:35:93'/>
> +  <plug type='bridge' bridge='virbr0' macTableManager='libvirt'/>
> +</networkport>
> diff --git a/tests/virnetworkportxml2xmldata/plug-bridge.xml b/tests/virnetworkportxml2xmldata/plug-bridge.xml
> new file mode 100644
> index 0000000000..6dd576e8a1
> --- /dev/null
> +++ b/tests/virnetworkportxml2xmldata/plug-bridge.xml
> @@ -0,0 +1,12 @@
> +<networkport>
> +  <uuid>5d744f21-ba4a-4d6e-bdb2-30a35ff3207d</uuid>
> +  <owner>
> +    <name>memtest</name>
> +    <uuid>d54df46f-1ab5-4a22-8618-4560ef5fac2c</uuid>
> +  </owner>
> +  <group>web1</group>
> +  <mac address='52:54:00:7b:35:93'/>
> +  <class id='1729'/>
> +  <rxfilters trustGuest='yes'/>


Where were you back in 1897 (or whenever - it was a long time ago) when 
I posted a patch with "trustGuestRxFilters" as a strawman hoping for 
counter proposals, and nobody offered an alternative? :-P


> +  <plug type='bridge' bridge='virbr0'/>
> +</networkport>
> diff --git a/tests/virnetworkportxml2xmldata/plug-direct.xml b/tests/virnetworkportxml2xmldata/plug-direct.xml
> new file mode 100644
> index 0000000000..81554b4579
> --- /dev/null
> +++ b/tests/virnetworkportxml2xmldata/plug-direct.xml
> @@ -0,0 +1,12 @@
> +<networkport>
> +  <uuid>5d744f21-ba4a-4d6e-bdb2-30a35ff3207d</uuid>
> +  <owner>
> +    <name>memtest</name>
> +    <uuid>d54df46f-1ab5-4a22-8618-4560ef5fac2c</uuid>
> +  </owner>
> +  <mac address='52:54:00:7b:35:93'/>
> +  <virtualport type='802.1Qbg'>
> +    <parameters managerid='11' typeid='1193047' typeidversion='2'/>
> +  </virtualport>
> +  <plug type='direct' dev='ens3' mode='vepa'/>
> +</networkport>
> diff --git a/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml b/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml
> new file mode 100644
> index 0000000000..cc4419f3fd
> --- /dev/null
> +++ b/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml
> @@ -0,0 +1,12 @@
> +<networkport>
> +  <uuid>5d744f21-ba4a-4d6e-bdb2-30a35ff3207d</uuid>
> +  <owner>
> +    <name>memtest</name>
> +    <uuid>d54df46f-1ab5-4a22-8618-4560ef5fac2c</uuid>
> +  </owner>
> +  <mac address='52:54:00:7b:35:93'/>
> +  <plug type='hostdev-pci' managed='yes'>
> +    <driver name='vfio'/>
> +    <address domain='0x0001' bus='0x02' slot='0x03' function='0x4'/>
> +  </plug>
> +</networkport>
> diff --git a/tests/virnetworkportxml2xmldata/plug-none.xml b/tests/virnetworkportxml2xmldata/plug-none.xml
> new file mode 100644
> index 0000000000..ed7199ec8c
> --- /dev/null
> +++ b/tests/virnetworkportxml2xmldata/plug-none.xml
> @@ -0,0 +1,8 @@
> +<networkport>
> +  <uuid>5d744f21-ba4a-4d6e-bdb2-30a35ff3207d</uuid>
> +  <owner>
> +    <name>memtest</name>
> +    <uuid>d54df46f-1ab5-4a22-8618-4560ef5fac2c</uuid>
> +  </owner>
> +  <mac address='52:54:00:7b:35:93'/>
> +</networkport>
> diff --git a/tests/virnetworkportxml2xmltest.c b/tests/virnetworkportxml2xmltest.c
> new file mode 100644
> index 0000000000..bb0ae8a8d5
> --- /dev/null
> +++ b/tests/virnetworkportxml2xmltest.c
> @@ -0,0 +1,104 @@
> +/*
> + * virnetworkportxml2xmltest.c: network port XML processing test suite
> + *
> + * 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 <unistd.h>
> +
> +#include <sys/types.h>
> +#include <fcntl.h>
> +
> +#include "internal.h"
> +#include "testutils.h"
> +#include "virnetworkportdef.h"
> +#include "virstring.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_NONE
> +
> +
> +static int
> +testCompareXMLToXMLFiles(const char *expected)
> +{
> +    char *actual = NULL;
> +    int ret = -1;
> +    virNetworkPortDefPtr dev = NULL;
> +
> +    if (!(dev = virNetworkPortDefParseFile(expected)))
> +        goto cleanup;
> +
> +    if (!(actual = virNetworkPortDefFormat(dev)))
> +        goto cleanup;
> +
> +    if (virTestCompareToFile(actual, expected) < 0)
> +        goto cleanup;
> +
> +    ret = 0;
> + cleanup:
> +    VIR_FREE(actual);
> +    virNetworkPortDefFree(dev);
> +    return ret;
> +}
> +
> +struct testInfo {
> +    const char *name;
> +};
> +
> +static int
> +testCompareXMLToXMLHelper(const void *data)
> +{
> +    const struct testInfo *info = data;
> +    int ret = -1;
> +    char *xml = NULL;
> +
> +    if (virAsprintf(&xml, "%s/virnetworkportxml2xmldata/%s.xml",
> +                    abs_srcdir, info->name) < 0)
> +        goto cleanup;
> +
> +    ret = testCompareXMLToXMLFiles(xml);
> +
> + cleanup:
> +    VIR_FREE(xml);
> +
> +    return ret;
> +}
> +
> +static int
> +mymain(void)
> +{
> +    int ret = 0;
> +
> +#define DO_TEST(name) \
> +    do { \
> +        const struct testInfo info = {name}; \
> +        if (virTestRun("virnetworkportdeftest " name, \
> +                       testCompareXMLToXMLHelper, &info) < 0) \
> +            ret = -1; \
> +    } while (0)
> +
> +    DO_TEST("plug-none");
> +    DO_TEST("plug-bridge");
> +    DO_TEST("plug-bridge-mactbl");
> +    DO_TEST("plug-direct");
> +    DO_TEST("plug-hostdev-pci");
> +
> +    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> +}
> +
> +VIR_TEST_MAIN(mymain)





More information about the libvir-list mailing list