virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
                        xmlNodePtr node,
                        xmlXPathContextPtr ctxt,
                        unsigned int flags)
{
    virDomainNetDefPtr def;
    virDomainHostdevDefPtr hostdev;
    xmlNodePtr cur;
    xmlNodePtr tmpNode;
    virHashTablePtr filterparams = NULL;
    virDomainActualNetDefPtr actual = NULL;
    VIR_XPATH_NODE_AUTORESTORE(ctxt);
    virDomainChrSourceReconnectDef reconnect = {0};
    int rv, val;
    g_autofree char *macaddr = NULL;
    g_autofree char *type = NULL;
    g_autofree char *network = NULL;
    g_autofree char *portgroup = NULL;
    g_autofree char *portid = NULL;
    g_autofree char *bridge = NULL;
    g_autofree char *dev = NULL;
    g_autofree char *ifname = NULL;
    g_autofree char *managed_tap = NULL;
    g_autofree char *ifname_guest = NULL;
    g_autofree char *ifname_guest_actual = NULL;
    g_autofree char *script = NULL;
    g_autofree char *address = NULL;
    g_autofree char *port = NULL;
    g_autofree char *localaddr = NULL;
    g_autofree char *localport = NULL;
    g_autofree char *model = NULL;
    g_autofree char *backend = NULL;
    g_autofree char *txmode = NULL;
    g_autofree char *ioeventfd = NULL;
    g_autofree char *event_idx = NULL;
    g_autofree char *queues = NULL;
    g_autofree char *rx_queue_size = NULL;
    g_autofree char *tx_queue_size = NULL;
    g_autofree char *str = NULL;
    g_autofree char *filter = NULL;
    g_autofree char *internal = NULL;
    g_autofree char *mode = NULL;
    g_autofree char *linkstate = NULL;
    g_autofree char *addrtype = NULL;
    g_autofree char *domain_name = NULL;
    g_autofree char *vhostuser_mode = NULL;
    g_autofree char *vhostuser_path = NULL;
    g_autofree char *vhostuser_type = NULL;
    g_autofree char *trustGuestRxFilters = NULL;
    g_autofree char *vhost_path = NULL;
    g_autofree char *teamingType = NULL;
    g_autofree char *teamingPersistent = NULL;
    const char *prefix = xmlopt ? xmlopt->config.netPrefix : NULL;

    if (!(def = virDomainNetDefNew(xmlopt)))
        return NULL;

    ctxt->node = node;

    type = virXMLPropString(node, "type");
    if (type != NULL) {
        if ((int)(def->type = virDomainNetTypeFromString(type)) < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown interface type '%s'"), type);
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_NET_TYPE_USER;
    }

    trustGuestRxFilters = virXMLPropString(node, "trustGuestRxFilters");
    if (trustGuestRxFilters &&
        ((def->trustGuestRxFilters
          = virTristateBoolTypeFromString(trustGuestRxFilters)) <= 0)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown trustGuestRxFilters value '%s'"),
                       trustGuestRxFilters);
        goto error;
    }

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (virXMLNodeNameEqual(cur, "source")) {
                xmlNodePtr tmpnode = ctxt->node;

                ctxt->node = cur;
                if (virDomainNetIPInfoParseXML(_("interface host IP"),
                                               ctxt, &def->hostIP) < 0)
                    goto error;
                ctxt->node = tmpnode;
            }
            if (!macaddr && virXMLNodeNameEqual(cur, "mac")) {
                macaddr = virXMLPropString(cur, "address");
            } else if (!network &&
                       def->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
                       virXMLNodeNameEqual(cur, "source")) {
                network = virXMLPropString(cur, "network");
                portgroup = virXMLPropString(cur, "portgroup");
                if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
                    portid = virXMLPropString(cur, "portid");
            } else if (!internal &&
                       def->type == VIR_DOMAIN_NET_TYPE_INTERNAL &&
                       virXMLNodeNameEqual(cur, "source")) {
                internal = virXMLPropString(cur, "name");
            } else if (!bridge &&
                       def->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
                       virXMLNodeNameEqual(cur, "source")) {
                bridge = virXMLPropString(cur, "bridge");
            } else if (!dev && def->type == VIR_DOMAIN_NET_TYPE_DIRECT &&
                       virXMLNodeNameEqual(cur, "source")) {
                dev  = virXMLPropString(cur, "dev");
                mode = virXMLPropString(cur, "mode");
            } else if (!dev && def->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
                       virXMLNodeNameEqual(cur, "source")) {
                /* This clause is only necessary because from 2010 to
                 * 2016 it was possible (but never documented) to
                 * configure the name of the guest-side interface of
                 * an openvz domain with <source dev='blah'/>.  That
                 * was blatant misuse of <source>, so was likely
                 * (hopefully) never used, but just in case there was
                 * somebody using it, we need to generate an error. If
                 * the openvz driver is ever deprecated, this clause
                 * can be removed from here.
                 */
                if ((dev = virXMLPropString(cur, "dev"))) {
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("Invalid attempt to set <interface type='ethernet'> "
                                     "device name with <source dev='%s'/>. "
                                     "Use <target dev='%s'/> (for host-side) "
                                     "or <guest dev='%s'/> (for guest-side) instead."),
                                   dev, dev, dev);
                    goto error;
                }
            } else if (!vhostuser_path && !vhostuser_mode && !vhostuser_type
                       && def->type == VIR_DOMAIN_NET_TYPE_VHOSTUSER
                       && virXMLNodeNameEqual(cur, "source")) {
                vhostuser_type = virXMLPropString(cur, "type");
                vhostuser_path = virXMLPropString(cur, "path");
                vhostuser_mode = virXMLPropString(cur, "mode");
                if (virDomainChrSourceReconnectDefParseXML(&reconnect, cur, ctxt) < 0)
                    goto error;

            } else if (!def->virtPortProfile
                       && virXMLNodeNameEqual(cur, "virtualport")) {
                if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
                    if (!(def->virtPortProfile
                          = virNetDevVPortProfileParse(cur,
                                                       VIR_VPORT_XML_GENERATE_MISSING_DEFAULTS))) {
                        goto error;
                    }
                } else if (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
                           def->type == VIR_DOMAIN_NET_TYPE_DIRECT ||
                           def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
                    if (!(def->virtPortProfile
                          = virNetDevVPortProfileParse(cur,
                                                       VIR_VPORT_XML_GENERATE_MISSING_DEFAULTS|
                                                       VIR_VPORT_XML_REQUIRE_ALL_ATTRIBUTES|
                                                       VIR_VPORT_XML_REQUIRE_TYPE))) {
                        goto error;
                    }
                } else {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("<virtualport> element unsupported for"
                                     " <interface type='%s'>"), type);
                    goto error;
                }
            } else if (!address &&
                       (def->type == VIR_DOMAIN_NET_TYPE_SERVER ||
                        def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
                        def->type == VIR_DOMAIN_NET_TYPE_MCAST ||
                        def->type == VIR_DOMAIN_NET_TYPE_UDP) &&
                       virXMLNodeNameEqual(cur, "source")) {
                address = virXMLPropString(cur, "address");
                port = virXMLPropString(cur, "port");
                if (!localaddr && def->type == VIR_DOMAIN_NET_TYPE_UDP) {
                    xmlNodePtr tmpnode = ctxt->node;
                    ctxt->node = cur;
                    if ((tmpNode = virXPathNode("./local", ctxt))) {
                        localaddr = virXMLPropString(tmpNode, "address");
                        localport = virXMLPropString(tmpNode, "port");
                    }
                    ctxt->node = tmpnode;
                }
            } else if (!ifname &&
                       virXMLNodeNameEqual(cur, "target")) {
                ifname = virXMLPropString(cur, "dev");
                managed_tap = virXMLPropString(cur, "managed");
            } else if ((!ifname_guest || !ifname_guest_actual) &&
                       virXMLNodeNameEqual(cur, "guest")) {
                ifname_guest = virXMLPropString(cur, "dev");
                ifname_guest_actual = virXMLPropString(cur, "actual");
            } else if (!linkstate &&
                       virXMLNodeNameEqual(cur, "link")) {
                linkstate = virXMLPropString(cur, "state");
            } else if (!script &&
                       virXMLNodeNameEqual(cur, "script")) {
                script = virXMLPropString(cur, "path");
            } else if (!domain_name &&
                       virXMLNodeNameEqual(cur, "backenddomain")) {
                domain_name = virXMLPropString(cur, "name");
            } else if (virXMLNodeNameEqual(cur, "model")) {
                model = virXMLPropString(cur, "type");
            } else if (virXMLNodeNameEqual(cur, "driver")) {
                backend = virXMLPropString(cur, "name");
                txmode = virXMLPropString(cur, "txmode");
                ioeventfd = virXMLPropString(cur, "ioeventfd");
                event_idx = virXMLPropString(cur, "event_idx");
                queues = virXMLPropString(cur, "queues");
                rx_queue_size = virXMLPropString(cur, "rx_queue_size");
                tx_queue_size = virXMLPropString(cur, "tx_queue_size");

                if (virDomainVirtioOptionsParseXML(cur, &def->virtio) < 0)
                    goto error;
            } else if (virXMLNodeNameEqual(cur, "filterref")) {
                if (filter) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("Invalid specification of multiple <filterref>s "
                                     "in a single <interface>"));
                    goto error;
                }
                filter = virXMLPropString(cur, "filter");
                virHashFree(filterparams);
                filterparams = virNWFilterParseParamAttributes(cur);
            } else if (virXMLNodeNameEqual(cur, "boot")) {
                /* boot is parsed as part of virDomainDeviceInfoParseXML */
            } else if (!actual &&
                       (flags & VIR_DOMAIN_DEF_PARSE_ACTUAL_NET) &&
                       def->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
                       virXMLNodeNameEqual(cur, "actual")) {
                if (virDomainActualNetDefParseXML(cur, ctxt, def,
                                                  &actual, flags) < 0) {
                    goto error;
                }
            } else if (virXMLNodeNameEqual(cur, "bandwidth")) {
                if (virNetDevBandwidthParse(&def->bandwidth,
                                            NULL,
                                            cur,
                                            def->type == VIR_DOMAIN_NET_TYPE_NETWORK) < 0)
                    goto error;
            } else if (virXMLNodeNameEqual(cur, "vlan")) {
                if (virNetDevVlanParse(cur, ctxt, &def->vlan) < 0)
                    goto error;
            } else if (virXMLNodeNameEqual(cur, "backend")) {
                char *tmp = NULL;

                if ((tmp = virXMLPropString(cur, "tap")))
                    def->backend.tap = virFileSanitizePath(tmp);
                VIR_FREE(tmp);

                if (!vhost_path && (tmp = virXMLPropString(cur, "vhost")))
                    vhost_path = virFileSanitizePath(tmp);
                VIR_FREE(tmp);
            } else if (virXMLNodeNameEqual(cur, "teaming") &&
                       !teamingType && !teamingPersistent) {
                teamingType = virXMLPropString(cur, "type");
                teamingPersistent =  virXMLPropString(cur, "persistent");
            }
        }
        cur = cur->next;
    }

    if (macaddr) {
        if (virMacAddrParse((const char *)macaddr, &def->mac) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("unable to parse mac address '%s'"),
                           (const char *)macaddr);
            goto error;
        }
        if (virMacAddrIsMulticast(&def->mac)) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("expected unicast mac address, found multicast '%s'"),
                           (const char *)macaddr);
            goto error;
        }
    } else {
        virDomainNetGenerateMAC(xmlopt, &def->mac);
        def->mac_generated = true;
    }

    if (virDomainDeviceInfoParseXML(xmlopt, node, &def->info,
                                    flags | VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT
                                    | VIR_DOMAIN_DEF_PARSE_ALLOW_ROM) < 0) {
        goto error;
    }

    if (model != NULL &&
        virDomainNetSetModelString(def, model) < 0)
        goto error;

    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_NETWORK:
        if (network == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'network' attribute "
                             "specified with <interface type='network'/>"));
            goto error;
        }
        if (portid &&
            virUUIDParse(portid, def->data.network.portid) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to parse port id '%s'"), portid);
            goto error;
        }

        def->data.network.name = g_steal_pointer(&network);
        def->data.network.portgroup = g_steal_pointer(&portgroup);
        def->data.network.actual = g_steal_pointer(&actual);
        break;

    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
        if (!virDomainNetIsVirtioModel(def)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Wrong or no <model> 'type' attribute "
                             "specified with <interface type='vhostuser'/>. "
                             "vhostuser requires the virtio-net* frontend"));
            goto error;
        }

        if (STRNEQ_NULLABLE(vhostuser_type, "unix")) {
            if (vhostuser_type)
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Type='%s' unsupported for"
                                 " <interface type='vhostuser'>"),
                               vhostuser_type);
            else
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("No <source> 'type' attribute "
                                 "specified for <interface "
                                 "type='vhostuser'>"));
            goto error;
        }

        if (vhostuser_path == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'path' attribute "
                             "specified with <interface "
                             "type='vhostuser'/>"));
            goto error;
        }

        if (vhostuser_mode == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'mode' attribute "
                             "specified with <interface "
                             "type='vhostuser'/>"));
            goto error;
        }

        if (!(def->data.vhostuser = virDomainChrSourceDefNew(xmlopt)))
            goto error;

        def->data.vhostuser->type = VIR_DOMAIN_CHR_TYPE_UNIX;
        def->data.vhostuser->data.nix.path = g_steal_pointer(&vhostuser_path);

        if (STREQ(vhostuser_mode, "server")) {
            def->data.vhostuser->data.nix.listen = true;
            if (reconnect.enabled == VIR_TRISTATE_BOOL_YES) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("'reconnect' attribute  unsupported "
                                 "'server' mode for <interface type='vhostuser'>"));
                goto error;
           }
        } else if (STREQ(vhostuser_mode, "client")) {
            def->data.vhostuser->data.nix.listen = false;
            def->data.vhostuser->data.nix.reconnect = reconnect;
        } else {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Wrong <source> 'mode' attribute "
                             "specified with <interface "
                             "type='vhostuser'/>"));
            goto error;
        }
        break;

    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        if (bridge == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'bridge' attribute "
                             "specified with <interface type='bridge'/>"));
            goto error;
        }
        def->data.bridge.brname = g_steal_pointer(&bridge);
        break;

    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_MCAST:
    case VIR_DOMAIN_NET_TYPE_UDP:
        if (port == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'port' attribute "
                             "specified with socket interface"));
            goto error;
        }
        if (virStrToLong_i(port, NULL, 10, &def->data.socket.port) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <source> 'port' attribute "
                             "with socket interface"));
            goto error;
        }

        if (address == NULL) {
            if (def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
                def->type == VIR_DOMAIN_NET_TYPE_MCAST ||
                def->type == VIR_DOMAIN_NET_TYPE_UDP) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("No <source> 'address' attribute "
                                 "specified with socket interface"));
                goto error;
            }
        } else {
            def->data.socket.address = g_steal_pointer(&address);
        }

        if (def->type != VIR_DOMAIN_NET_TYPE_UDP)
            break;

        if (localport == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <local> 'port' attribute "
                             "specified with socket interface"));
            goto error;
        }
        if (virStrToLong_i(localport, NULL, 10, &def->data.socket.localport) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Cannot parse <local> 'port' attribute "
                             "with socket interface"));
            goto error;
        }

        if (localaddr == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <local> 'address' attribute "
                             "specified with socket interface"));
            goto error;
        } else {
            def->data.socket.localaddr = g_steal_pointer(&localaddr);
        }
        break;

    case VIR_DOMAIN_NET_TYPE_INTERNAL:
        if (internal == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'name' attribute specified "
                             "with <interface type='internal'/>"));
            goto error;
        }
        def->data.internal.name = g_steal_pointer(&internal);
        break;

    case VIR_DOMAIN_NET_TYPE_DIRECT:
        if (dev == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No <source> 'dev' attribute specified "
                             "with <interface type='direct'/>"));
            goto error;
        }

        if (mode != NULL) {
            if ((val = virNetDevMacVLanModeTypeFromString(mode)) < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Unknown mode has been specified"));
                goto error;
            }
            def->data.direct.mode = val;
        } else {
            def->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
        }

        def->data.direct.linkdev = g_steal_pointer(&dev);

        if (ifname &&
            flags & VIR_DOMAIN_DEF_PARSE_INACTIVE &&
            (STRPREFIX(ifname, VIR_NET_GENERATED_MACVTAP_PREFIX) ||
             STRPREFIX(ifname, VIR_NET_GENERATED_MACVLAN_PREFIX))) {
            VIR_FREE(ifname);
        }

        break;

    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        hostdev = &def->data.hostdev.def;
        hostdev->parentnet = def;
        hostdev->info = &def->info;
        /* The helper function expects type to already be found and
         * passed in as a string, since it is in a different place in
         * NetDef vs HostdevDef.
         */
        addrtype = virXPathString("string(./source/address/@type)", ctxt);
        /* if not explicitly stated, source/vendor implies usb device */
        if (!addrtype && virXPathNode("./source/vendor", ctxt))
            addrtype = g_strdup("usb");
        hostdev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        if (virDomainHostdevDefParseXMLSubsys(node, ctxt, addrtype,
                                              hostdev, flags) < 0) {
            goto error;
        }
        break;

    case VIR_DOMAIN_NET_TYPE_ETHERNET:
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
    }

    if (virDomainNetIPInfoParseXML(_("guest interface"),
                                   ctxt, &def->guestIP) < 0)
        goto error;

    if (managed_tap) {
        bool state = false;
        if (virStringParseYesNo(managed_tap, &state) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("invalid 'managed' value '%s'"),
                           managed_tap);
            goto error;
        }
        def->managed_tap = virTristateBoolFromBool(state);
    }

    if (def->managed_tap != VIR_TRISTATE_BOOL_NO && ifname &&
        (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
        (STRPREFIX(ifname, VIR_NET_GENERATED_TAP_PREFIX) ||
         (prefix && STRPREFIX(ifname, prefix)))) {
        /* An auto-generated target name, blank it out */
        VIR_FREE(ifname);
    }

    if (script != NULL)
        def->script = g_steal_pointer(&script);
    if (domain_name != NULL)
        def->domain_name = g_steal_pointer(&domain_name);
    if (ifname != NULL)
        def->ifname = g_steal_pointer(&ifname);
    if (ifname_guest != NULL)
        def->ifname_guest = g_steal_pointer(&ifname_guest);
    if (ifname_guest_actual != NULL)
        def->ifname_guest_actual = g_steal_pointer(&ifname_guest_actual);

    if (def->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
        virDomainNetIsVirtioModel(def)) {
        if (backend != NULL) {
            if ((val = virDomainNetBackendTypeFromString(backend)) < 0 ||
                val == VIR_DOMAIN_NET_BACKEND_TYPE_DEFAULT) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Unknown interface <driver name='%s'> "
                                 "has been specified"),
                               backend);
                goto error;
            }
            def->driver.virtio.name = val;
        }
        if (txmode != NULL) {
            if ((val = virDomainNetVirtioTxModeTypeFromString(txmode)) < 0 ||
                val == VIR_DOMAIN_NET_VIRTIO_TX_MODE_DEFAULT) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Unknown interface <driver txmode='%s'> "
                                 "has been specified"),
                               txmode);
                goto error;
            }
            def->driver.virtio.txmode = val;
        }
        if (ioeventfd) {
            if ((val = virTristateSwitchTypeFromString(ioeventfd)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown interface ioeventfd mode '%s'"),
                               ioeventfd);
                goto error;
            }
            def->driver.virtio.ioeventfd = val;
        }
        if (event_idx) {
            if ((val = virTristateSwitchTypeFromString(event_idx)) <= 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown interface event_idx mode '%s'"),
                               event_idx);
                goto error;
            }
            def->driver.virtio.event_idx = val;
        }
        if (queues) {
            unsigned int q;
            if (virStrToLong_uip(queues, NULL, 10, &q) < 0) {
                virReportError(VIR_ERR_XML_DETAIL,
                               _("'queues' attribute must be positive number: %s"),
                               queues);
                goto error;
            }
            if (q > 1)
                def->driver.virtio.queues = q;
        }
        if (rx_queue_size) {
            unsigned int q;
            if (virStrToLong_uip(rx_queue_size, NULL, 10, &q) < 0) {
                virReportError(VIR_ERR_XML_DETAIL,
                               _("'rx_queue_size' attribute must be positive number: %s"),
                               rx_queue_size);
                goto error;
            }
            def->driver.virtio.rx_queue_size = q;
        }
        if (tx_queue_size) {
            unsigned int q;
            if (virStrToLong_uip(tx_queue_size, NULL, 10, &q) < 0) {
                virReportError(VIR_ERR_XML_DETAIL,
                               _("'tx_queue_size' attribute must be positive number: %s"),
                               tx_queue_size);
                goto error;
            }
            def->driver.virtio.tx_queue_size = q;
        }

        if ((tmpNode = virXPathNode("./driver/host", ctxt))) {
            if ((str = virXMLPropString(tmpNode, "csum"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown host csum mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.host.csum = val;
            }
            VIR_FREE(str);
            if ((str = virXMLPropString(tmpNode, "gso"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown host gso mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.host.gso = val;
            }
            VIR_FREE(str);
            if ((str = virXMLPropString(tmpNode, "tso4"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown host tso4 mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.host.tso4 = val;
            }
            VIR_FREE(str);
            if ((str = virXMLPropString(tmpNode, "tso6"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown host tso6 mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.host.tso6 = val;
            }
            VIR_FREE(str);
            if ((str = virXMLPropString(tmpNode, "ecn"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown host ecn mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.host.ecn = val;
            }
            VIR_FREE(str);
            if ((str = virXMLPropString(tmpNode, "ufo"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown host ufo mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.host.ufo = val;
            }
            VIR_FREE(str);
            if ((str = virXMLPropString(tmpNode, "mrg_rxbuf"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown host mrg_rxbuf mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.host.mrg_rxbuf = val;
            }
            VIR_FREE(str);
        }

        if ((tmpNode = virXPathNode("./driver/guest", ctxt))) {
            if ((str = virXMLPropString(tmpNode, "csum"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown guest csum mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.guest.csum = val;
            }
            VIR_FREE(str);
            if ((str = virXMLPropString(tmpNode, "tso4"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown guest tso4 mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.guest.tso4 = val;
            }
            VIR_FREE(str);
            if ((str = virXMLPropString(tmpNode, "tso6"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown guest tso6 mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.guest.tso6 = val;
            }
            VIR_FREE(str);
            if ((str = virXMLPropString(tmpNode, "ecn"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown guest ecn mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.guest.ecn = val;
            }
            VIR_FREE(str);
            if ((str = virXMLPropString(tmpNode, "ufo"))) {
                if ((val = virTristateSwitchTypeFromString(str)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown guest ufo mode '%s'"),
                                   str);
                    goto error;
                }
                def->driver.virtio.guest.ufo = val;
            }
        }
        def->backend.vhost = g_steal_pointer(&vhost_path);
    }

    def->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DEFAULT;
    if (linkstate != NULL) {
        if ((def->linkstate = virDomainNetInterfaceLinkStateTypeFromString(linkstate)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown interface link state '%s'"),
                           linkstate);
            goto error;
        }
    }

    if (filter != NULL) {
        switch (def->type) {
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
        case VIR_DOMAIN_NET_TYPE_NETWORK:
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
            def->filter = g_steal_pointer(&filter);
            def->filterparams = g_steal_pointer(&filterparams);
            break;
        case VIR_DOMAIN_NET_TYPE_USER:
        case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
        case VIR_DOMAIN_NET_TYPE_INTERNAL:
        case VIR_DOMAIN_NET_TYPE_DIRECT:
        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        case VIR_DOMAIN_NET_TYPE_UDP:
            break;
        case VIR_DOMAIN_NET_TYPE_LAST:
        default:
            virReportEnumRangeError(virDomainNetType, def->type);
            goto error;
        }
    }

    if (teamingType) {
        int tmpTeaming;

        if ((tmpTeaming = virDomainNetTeamingTypeFromString(teamingType)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown teaming type '%s'"),
                           teamingType);
            goto error;
        }
        def->teaming.type = tmpTeaming;
    }
    def->teaming.persistent = g_steal_pointer(&teamingPersistent);

    rv = virXPathULong("string(./tune/sndbuf)", ctxt, &def->tune.sndbuf);
    if (rv >= 0) {
        def->tune.sndbuf_specified = true;
    } else if (rv == -2) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("sndbuf must be a positive integer"));
        goto error;
    }

    if (virXPathUInt("string(./mtu/@size)", ctxt, &def->mtu) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("malformed mtu size"));
        goto error;
    }

    node = virXPathNode("./coalesce", ctxt);
    if (node) {
        def->coalesce = virDomainNetDefCoalesceParseXML(node, ctxt);
        if (!def->coalesce)
            goto error;
    }

    if (virNetworkPortOptionsParseXML(ctxt, &def->isolatedPort) < 0)
        goto error;

 cleanup:
    virDomainActualNetDefFree(actual);
    virHashFree(filterparams);
    return def;

 error:
    virDomainNetDefFree(def);
    def = NULL;
    goto cleanup;
}