diff --git a/docs/docs.html.in b/docs/docs.html.in
index d0ff844d0cbeb2799eff81cbb682ab61a5c46ee6..c8674e145750c4996dc9756bdfb0fb048f443de7 100644
--- a/docs/docs.html.in
+++ b/docs/docs.html.in
@@ -72,6 +72,7 @@
Description of the XML schemas for
domains,
networks,
+ network ports,
network filtering,
storage,
storage encryption,
diff --git a/docs/formatnetworkport.html.in b/docs/formatnetworkport.html.in
new file mode 100644
index 0000000000000000000000000000000000000000..554e5c65fc37b15047947c62160dc97ddadd29e0
--- /dev/null
+++ b/docs/formatnetworkport.html.in
@@ -0,0 +1,212 @@
+
+
+
+
+ Network XML format
+
+
+
+
+ This page provides an introduction to the network port XML format.
+ This stores information about the connection between an virtual
+ interface on a virtual domain's, and the virtual network it is
+ attached to.
+
+
+
+
+
+ The root element required for all virtual network ports is
+ named networkport
and has no configurable attributes
+ The network port XML format is available since
+ 5.5.0
+
+
+
+
+
+ The first elements provide basic metadata about the virtual
+ network port.
+
+
+
+<networkport
+ <uuid>7ae63b5f-fe96-4af0-a7c3-da04ba1b3f54</uuid>
+ <owner>
+ <uuid>06578fc1-c686-46fa-bc2c-220893b466a6</uuid>
+ <name>myguest<name>
+ </owner>
+ <group>webfront<group>
+ <mac address='52:54:0:7b:35:93'/>
+ ...
+
+
+ uuid
+ - The content of the
uuid
element provides
+ a globally unique identifier for the virtual network port.
+ The format must be RFC 4122 compliant, eg 3e3fce45-4f53-4fa7-bb32-11f34168b82b
.
+ If omitted when defining/creating a new network port, a random
+ UUID is generated.
+ - The
owner
node records the domain object that
+ is the owner of the network port. It contains two child nodes:
+
+ uuid
+ - The content of the
uuid
element provides
+ a globally unique identifier for the virtual domain.
+ name
+ - The unique name of the virtual domain
+
+
+ group
+ - The port group in the virtual network to which the
+ port belongs. Can be omitted if no port groups are
+ defined on the network.
+ mac
+ - The
address
attribute provides the MAC
+ address of the virtual port that will be see by the
+ guest. The MAC address must not start with 0xFE as this
+ byte is reserved for use on the host side of the port.
+
+
+
+
+
+
+ The following elements are common to one of more of the plug
+ types listed later
+
+
+
+ ...
+ <bandwidth>
+ <inbound average='1000' peak='5000' floor='200' burst='1024'/>
+ <outbound average='128' peak='256' burst='256'/>
+ </bandwidth>
+ <rxfilters trustGuest='yes'/>
+ <virtualport type='802.1Qbg'>
+ <parameters managerid='11' typeid='1193047' typeidversion='2'/>
+ </virtualport>
+ ...
+
+
+ bandwidth
+ - This part of the network port XML provides setting quality of service.
+ Incoming and outgoing traffic can be shaped independently.
+ The
bandwidth
element and its child elements are described
+ in the QoS section of
+ the Network XML. In addition the classID
attribute may
+ exist provide the ID of the traffic shaping class that is active.
+
+ rxfilters
+ - The
rxfilters
element property
+ trustGuest
provides the
+ capability for the host to detect and trust reports from the
+ guest regarding changes to the interface mac address and receive
+ filters by setting the attribute to yes
. The default
+ setting for the attribute is no
for security
+ reasons and support depends on the guest network device model as
+ well as the type of connection on the host - currently it is
+ only supported for the virtio device model and for macvtap
+ connections on the host.
+
+ virtualport
+ - The
virtualport
element describes metadata that
+ needs to be provided to the underlying network subsystem. It
+ is described in the domain XML
+ interface documentation.
+
+
+
+
+
+
+
+ The plug
element has varying content depending
+ on the value of the type
attribute.
+
+
+
+
+
+ The network
plug type refers to a managed virtual
+ network plug that is based on a traditional software bridge
+ device privately managed by libvirt.
+
+
+
+ ...
+ <plug type='network' bridge='virbr0'>
+ ...
+
+
+ The bridge
attribute provides the name of the
+ privately managed bridge device associated with the virtual
+ network.
+
+
+
+
+
+ The bridge
plug type refers to an externally
+ managed traditional software bridge.
+
+
+
+ ...
+ <plug type='bridge' bridge='br2'>
+ ...
+
+
+ The bridge
attribute provides the name of the
+ externally managed bridge device associated with the virtual
+ network.
+
+
+
+
+
+ The direct
plug type refers to a connection
+ directly to a physical network interface.
+
+
+
+ ...
+ <plug type='direct' dev='ens3' mode='vepa'/>
+ ...
+
+
+ The dev
attribute provides the name of the
+ physical network interface to which the port will be
+ connected. The mode
attribute describes
+ how the connection will be setup and takes the same
+ values described in the
+ domain XML.
+
+
+
+
+
+ The hostdev-pci
plug type refers to the
+ passthrough of a physical PCI device rather than emulation.
+
+
+
+ ...
+ <plug type='hostdev-pci' managed='yes'>
+ <driver name='vfio'/>
+ <address domain='0x0001' bus='0x02' slot='0x03' function='0x4'/>
+ </plug>
+ ...
+
+
+ The managed
attribute indicates who is responsible for
+ managing the PCI device in the host. When set to the value yes
+ libvirt is responsible for automatically detaching the device from host
+ drivers and resetting it if needed. If the value is no
,
+ some other party must ensure the device is not attached to any
+ host drivers.
+
+
+
+
diff --git a/docs/schemas/networkcommon.rng b/docs/schemas/networkcommon.rng
index 26995556d48decca4d0102b0f782a6c03bbe5c6e..fd1aac6485a52cd37e1cb444d7bdb5ed29507dc3 100644
--- a/docs/schemas/networkcommon.rng
+++ b/docs/schemas/networkcommon.rng
@@ -134,6 +134,11 @@
+
+
+
+
+
diff --git a/docs/schemas/networkport.rng b/docs/schemas/networkport.rng
new file mode 100644
index 0000000000000000000000000000000000000000..8cfc043a4078383a5b858a530a89f9d84dbb82e6
--- /dev/null
+++ b/docs/schemas/networkport.rng
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ network
+
+
+
+
+
+
+
+
+
+
+
+
+
+ bridge
+
+
+
+
+
+
+
+
+
+
+
+
+
+ direct
+
+
+
+
+
+
+ bridge
+ passthrough
+ private
+ vepa
+
+
+
+
+
+
+ hostdev-pci
+
+
+
+
+
+
+
+
+
+
+ kvm
+ vfio
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 59a2a0cb245b56393dac1d32f1362746edea507c..3b5b4925fdf6bf99b502171dc85a2d43177bb1fe 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -1788,6 +1788,7 @@ exit 0
%{_datadir}/libvirt/schemas/interface.rng
%{_datadir}/libvirt/schemas/network.rng
%{_datadir}/libvirt/schemas/networkcommon.rng
+%{_datadir}/libvirt/schemas/networkport.rng
%{_datadir}/libvirt/schemas/nodedev.rng
%{_datadir}/libvirt/schemas/nwfilter.rng
%{_datadir}/libvirt/schemas/nwfilter_params.rng
diff --git a/src/conf/Makefile.inc.am b/src/conf/Makefile.inc.am
index 3e9fdd1aeab4dfb1aec491f1822822a3e9c3a732..6b52ba674b5c67e47c8ea12151d2f93803a0f5db 100644
--- a/src/conf/Makefile.inc.am
+++ b/src/conf/Makefile.inc.am
@@ -7,6 +7,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 0000000000000000000000000000000000000000..379411e08833e643652721be5fe3261a267e7842
--- /dev/null
+++ b/src/conf/virnetworkportdef.c
@@ -0,0 +1,508 @@
+/*
+ * 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
+ * .
+ */
+
+#include
+
+#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", "network", "bridge", "direct", "hostdev-pci");
+
+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_NETWORK:
+ 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;
+
+ 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;
+ }
+
+ 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, &def->class_id,
+ 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_NETWORK:
+ 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, "\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ virUUIDFormat(def->uuid, uuid);
+ virBufferAsprintf(buf, "%s\n", uuid);
+
+ virBufferAddLit(buf, "\n");
+ virBufferAdjustIndent(buf, 2);
+ virBufferEscapeString(buf, "%s\n", def->ownername);
+ virUUIDFormat(def->owneruuid, uuid);
+ virBufferAsprintf(buf, "%s\n", uuid);
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "\n");
+
+ virBufferEscapeString(buf, "%s\n", def->group);
+
+ virMacAddrFormat(&def->mac, macaddr);
+ virBufferAsprintf(buf, "\n", macaddr);
+
+ if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
+ return -1;
+ if (def->bandwidth)
+ virNetDevBandwidthFormat(def->bandwidth, def->class_id, buf);
+ if (virNetDevVlanFormat(&def->vlan, buf) < 0)
+ return -1;
+ if (def->trustGuestRxFilters)
+ virBufferAsprintf(buf, "\n",
+ virTristateBoolTypeToString(def->trustGuestRxFilters));
+
+ if (def->plugtype != VIR_NETWORK_PORT_PLUG_TYPE_NONE) {
+ virBufferAsprintf(buf, "plugtype));
+
+ switch (def->plugtype) {
+ case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
+ break;
+
+ case VIR_NETWORK_PORT_PLUG_TYPE_NETWORK:
+ 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, "\n",
+ virNetworkForwardDriverNameTypeToString(
+ def->plug.hostdevpci.driver));
+
+ virPCIDeviceAddressFormat(buf, def->plug.hostdevpci.addr, false);
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "\n");
+ break;
+
+ case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
+ default:
+ virReportEnumRangeError(virNetworkPortPlugType, def->plugtype);
+ return -1;
+ }
+ }
+
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "\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 0000000000000000000000000000000000000000..3d42b9b6a2d7c27423cf095624c5090f49245351
--- /dev/null
+++ b/src/conf/virnetworkportdef.h
@@ -0,0 +1,109 @@
+/*
+ * 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
+ * .
+ *
+ */
+
+#pragma once
+
+#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_NETWORK,
+ 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; /* For TYPE_NETWORK & TYPE_BRIDGE */
+ struct {
+ char *linkdev;
+ int mode; /* enum virNetDevMacVLanMode from util/virnetdevmacvlan.h */
+ } direct;
+ struct {
+ virPCIDeviceAddress addr; /* PCI Address of device */
+ int driver; /* virNetworkForwardDriverNameType */
+ 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);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 8ee76645cd321d42563e8ef2cff99528c7731786..ab97f226c497f81d913e23bfa6b6d6e721a645aa 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1075,6 +1075,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 5ba529124a6363851d4ad23aaa063c46ac33f666..cbcfbe23ccb2791e9560de8637f855428c3ababc 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -149,6 +149,7 @@ EXTRA_DIST = \
virmockstathelpers.c \
virnetdaemondata \
virnetdevtestdata \
+ virnetworkportxml2xmldata \
virnwfilterbindingxml2xmldata \
virpcitestdata \
virscsidata \
@@ -335,6 +336,7 @@ endif WITH_YAJL
test_programs += \
networkxml2xmltest \
networkxml2xmlupdatetest \
+ virnetworkportxml2xmltest \
$(NULL)
if WITH_NETWORK
@@ -833,6 +835,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 0000000000000000000000000000000000000000..8036bc2e1c3ecdf82c4ebfd213bc5f78f28acddf
--- /dev/null
+++ b/tests/virnetworkportxml2xmldata/plug-bridge-mactbl.xml
@@ -0,0 +1,9 @@
+
+ 5d744f21-ba4a-4d6e-bdb2-30a35ff3207d
+
+ memtest
+ d54df46f-1ab5-4a22-8618-4560ef5fac2c
+
+
+
+
diff --git a/tests/virnetworkportxml2xmldata/plug-bridge.xml b/tests/virnetworkportxml2xmldata/plug-bridge.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e09fc45a9d0dd43c8820bda5bb5ef5cc3c82902f
--- /dev/null
+++ b/tests/virnetworkportxml2xmldata/plug-bridge.xml
@@ -0,0 +1,15 @@
+
+ 5d744f21-ba4a-4d6e-bdb2-30a35ff3207d
+
+ memtest
+ d54df46f-1ab5-4a22-8618-4560ef5fac2c
+
+ web1
+
+
+
+
+
+
+
+
diff --git a/tests/virnetworkportxml2xmldata/plug-direct.xml b/tests/virnetworkportxml2xmldata/plug-direct.xml
new file mode 100644
index 0000000000000000000000000000000000000000..81554b457918c9f632696edfb9c77db7114a846b
--- /dev/null
+++ b/tests/virnetworkportxml2xmldata/plug-direct.xml
@@ -0,0 +1,12 @@
+
+ 5d744f21-ba4a-4d6e-bdb2-30a35ff3207d
+
+ memtest
+ d54df46f-1ab5-4a22-8618-4560ef5fac2c
+
+
+
+
+
+
+
diff --git a/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml b/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cc4419f3fdfb23a9de021f4383c6840527292ca3
--- /dev/null
+++ b/tests/virnetworkportxml2xmldata/plug-hostdev-pci.xml
@@ -0,0 +1,12 @@
+
+ 5d744f21-ba4a-4d6e-bdb2-30a35ff3207d
+
+ memtest
+ d54df46f-1ab5-4a22-8618-4560ef5fac2c
+
+
+
+
+
+
+
diff --git a/tests/virnetworkportxml2xmldata/plug-network.xml b/tests/virnetworkportxml2xmldata/plug-network.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a3a8899148a87a926f86d920083b2f39e98798a7
--- /dev/null
+++ b/tests/virnetworkportxml2xmldata/plug-network.xml
@@ -0,0 +1,15 @@
+
+ 5d744f21-ba4a-4d6e-bdb2-30a35ff3207d
+
+ memtest
+ d54df46f-1ab5-4a22-8618-4560ef5fac2c
+
+ web1
+
+
+
+
+
+
+
+
diff --git a/tests/virnetworkportxml2xmldata/plug-none.xml b/tests/virnetworkportxml2xmldata/plug-none.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ed7199ec8ced33bd690ca552291f68873cb07896
--- /dev/null
+++ b/tests/virnetworkportxml2xmldata/plug-none.xml
@@ -0,0 +1,8 @@
+
+ 5d744f21-ba4a-4d6e-bdb2-30a35ff3207d
+
+ memtest
+ d54df46f-1ab5-4a22-8618-4560ef5fac2c
+
+
+
diff --git a/tests/virnetworkportxml2xmltest.c b/tests/virnetworkportxml2xmltest.c
new file mode 100644
index 0000000000000000000000000000000000000000..bb0ae8a8d5cd74e4ebfb8ba2f36c857a3e123e35
--- /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
+ * .
+ */
+
+#include
+
+#include
+
+#include
+#include
+
+#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)
diff --git a/tests/virschematest.c b/tests/virschematest.c
index 56bdcb2f883fcad5682623ac42c3f2082887f5e6..13c30acc30a75981f8adc9eaac190e25d58a82f4 100644
--- a/tests/virschematest.c
+++ b/tests/virschematest.c
@@ -227,6 +227,7 @@ mymain(void)
DO_TEST_DIR("interface.rng", "interfaceschemadata");
DO_TEST_DIR("network.rng", "../src/network", "networkxml2xmlin",
"networkxml2xmlout", "networkxml2confdata");
+ DO_TEST_DIR("networkport.rng", "virnetworkportxml2xmldata");
DO_TEST_DIR("nodedev.rng", "nodedevschemadata");
DO_TEST_DIR("nwfilter.rng", "nwfilterxml2xmlout", "../examples/xml/nwfilter");
DO_TEST_DIR("nwfilterbinding.rng", "virnwfilterbindingxml2xmldata");