conf: introduce virNetworkPortDefPtr struct and XML support

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@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2018-08-31 15:21:34 +01:00
parent c0c37de2d6
commit 4b4a981d60
18 changed files with 1185 additions and 0 deletions

View File

@ -72,6 +72,7 @@
<dd>Description of the XML schemas for
<a href="formatdomain.html">domains</a>,
<a href="formatnetwork.html">networks</a>,
<a href="formatnetworkport.html">network ports</a>,
<a href="formatnwfilter.html">network filtering</a>,
<a href="formatstorage.html">storage</a>,
<a href="formatstorageencryption.html">storage encryption</a>,

View File

@ -0,0 +1,212 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<h1>Network XML format</h1>
<ul id="toc">
</ul>
<p>
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.
</p>
<h2><a id="elements">Element and attribute overview</a></h2>
<p>
The root element required for all virtual network ports is
named <code>networkport</code> and has no configurable attributes
The network port XML format is available <span class="since">since
5.5.0</span>
</p>
<h3><a id="elementsMetadata">General metadata</a></h3>
<p>
The first elements provide basic metadata about the virtual
network port.
</p>
<pre>
&lt;networkport
&lt;uuid&gt;7ae63b5f-fe96-4af0-a7c3-da04ba1b3f54&lt;/uuid&gt;
&lt;owner&gt;
&lt;uuid&gt;06578fc1-c686-46fa-bc2c-220893b466a6&lt;/uuid&gt;
&lt;name&gt;myguest&lt;name&gt;
&lt;/owner&gt;
&lt;group&gt;webfront&lt;group&gt;
&lt;mac address='52:54:0:7b:35:93'/&gt;
...</pre>
<dl>
<dt><code>uuid</code></dt>
<dd>The content of the <code>uuid</code> element provides
a globally unique identifier for the virtual network port.
The format must be RFC 4122 compliant, eg <code>3e3fce45-4f53-4fa7-bb32-11f34168b82b</code>.
If omitted when defining/creating a new network port, a random
UUID is generated.</dd>
<dd>The <code>owner</code> node records the domain object that
is the owner of the network port. It contains two child nodes:
<dl>
<dt><code>uuid</code></dt>
<dd>The content of the <code>uuid</code> element provides
a globally unique identifier for the virtual domain.</dd>
<dt><code>name</code></dt>
<dd>The unique name of the virtual domain</dd>
</dl>
</dd>
<dt><code>group</code></dt>
<dd>The port group in the virtual network to which the
port belongs. Can be omitted if no port groups are
defined on the network.</dd>
<dt><code>mac</code></dt>
<dd>The <code>address</code> 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.
</dd>
</dl>
<h3><a id="elementsCommon">Common elements</a></h3>
<p>
The following elements are common to one of more of the plug
types listed later
</p>
<pre>
...
&lt;bandwidth&gt;
&lt;inbound average='1000' peak='5000' floor='200' burst='1024'/&gt;
&lt;outbound average='128' peak='256' burst='256'/&gt;
&lt;/bandwidth&gt;
&lt;rxfilters trustGuest='yes'/&gt;
&lt;virtualport type='802.1Qbg'&gt;
&lt;parameters managerid='11' typeid='1193047' typeidversion='2'/&gt;
&lt;/virtualport&gt;
...</pre>
<dl>
<dt><code>bandwidth</code></dt>
<dd>This part of the network port XML provides setting quality of service.
Incoming and outgoing traffic can be shaped independently.
The <code>bandwidth</code> element and its child elements are described
in the <a href="formatnetwork.html#elementQoS">QoS</a> section of
the Network XML. In addition the <code>classID</code> attribute may
exist provide the ID of the traffic shaping class that is active.
</dd>
<dt><code>rxfilters</code></dt>
<dd>The <code>rxfilters</code> element property
<code>trustGuest</code> 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 <code>yes</code>. The default
setting for the attribute is <code>no</code> 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.
</dd>
<dt><code>virtualport</code></dt>
<dd>The <code>virtualport</code> element describes metadata that
needs to be provided to the underlying network subsystem. It
is described in the domain XML
<a href="formatdomain.html#elementsNICS">interface documentation</a>.
</dd>
</dl>
<h3><a id="elementsPlug">Plugs</a></h3>
<p>
The <code>plug</code> element has varying content depending
on the value of the <code>type</code> attribute.
</p>
<h4><a id="elementsPlugNetwork">Network</a></h4>
<p>
The <code>network</code> plug type refers to a managed virtual
network plug that is based on a traditional software bridge
device privately managed by libvirt.
</p>
<pre>
...
&lt;plug type='network' bridge='virbr0'&gt;
...</pre>
<p>
The <code>bridge</code> attribute provides the name of the
privately managed bridge device associated with the virtual
network.
</p>
<h4><a id="elementsPlugNetwork">Bridge</a></h4>
<p>
The <code>bridge</code> plug type refers to an externally
managed traditional software bridge.
</p>
<pre>
...
&lt;plug type='bridge' bridge='br2'&gt;
...</pre>
<p>
The <code>bridge</code> attribute provides the name of the
externally managed bridge device associated with the virtual
network.
</p>
<h4><a id="elementsPlugNetwork">Direct</a></h4>
<p>
The <code>direct</code> plug type refers to a connection
directly to a physical network interface.
</p>
<pre>
...
&lt;plug type='direct' dev='ens3' mode='vepa'/&gt;
...</pre>
<p>
The <code>dev</code> attribute provides the name of the
physical network interface to which the port will be
connected. The <code>mode</code> attribute describes
how the connection will be setup and takes the same
values described in the
<a href="formatdomain.html#elementsNICSDirect">domain XML</a>.
</p>
<h4><a id="elementsPlugNetwork">Host PCI</a></h4>
<p>
The <code>hostdev-pci</code> plug type refers to the
passthrough of a physical PCI device rather than emulation.
</p>
<pre>
...
&lt;plug type='hostdev-pci' managed='yes'&gt;
&lt;driver name='vfio'/&gt;
&lt;address domain='0x0001' bus='0x02' slot='0x03' function='0x4'/&gt;
&lt;/plug&gt;
...</pre>
<p>
The <code>managed</code> attribute indicates who is responsible for
managing the PCI device in the host. When set to the value <code>yes</code>
libvirt is responsible for automatically detaching the device from host
drivers and resetting it if needed. If the value is <code>no</code>,
some other party must ensure the device is not attached to any
host drivers.
</p>
</body>
</html>

View File

@ -134,6 +134,11 @@
<define name="bandwidth">
<element name="bandwidth">
<optional>
<attribute name="classID">
<ref name="positiveInteger"/>
</attribute>
</optional>
<interleave>
<optional>
<element name="inbound">

View File

@ -0,0 +1,154 @@
<?xml version="1.0"?>
<!-- A Relax NG schema for the libvirt network port XML format -->
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<include href='basictypes.rng'/>
<include href='networkcommon.rng'/>
<start>
<ref name="networkport"/>
</start>
<define name="networkport">
<element name="networkport">
<interleave>
<element name="uuid">
<ref name="UUID"/>
</element>
<ref name="owner"/>
<ref name="mac"/>
<optional>
<ref name="group"/>
</optional>
<optional>
<ref name="rxfilters"/>
</optional>
<optional>
<ref name="virtualPortProfile"/>
</optional>
<optional>
<ref name="bandwidth"/>
</optional>
<optional>
<ref name="plug"/>
</optional>
</interleave>
</element>
</define>
<define name="owner">
<element name="owner">
<element name="name">
<text/>
</element>
<element name="uuid">
<ref name="UUID"/>
</element>
</element>
</define>
<define name="mac">
<element name="mac">
<attribute name="address">
<ref name="uniMacAddr"/>
</attribute>
<empty/>
</element>
</define>
<define name="group">
<element name="group">
<ref name="deviceName"/>
</element>
</define>
<define name="rxfilters">
<element name="rxfilters">
<attribute name="trustGuest">
<ref name="virYesNo"/>
</attribute>
</element>
</define>
<define name="plug">
<element name="plug">
<choice>
<ref name="plugnetwork"/>
<ref name="plugbridge"/>
<ref name="plugdirect"/>
<ref name="plughostdevpci"/>
</choice>
</element>
</define>
<define name="plugnetwork">
<attribute name="type">
<value>network</value>
</attribute>
<attribute name="bridge">
<ref name="deviceName"/>
</attribute>
<optional>
<attribute name="macTableManager">
<ref name="macTableManager"/>
</attribute>
</optional>
</define>
<define name="plugbridge">
<attribute name="type">
<value>bridge</value>
</attribute>
<attribute name="bridge">
<ref name="deviceName"/>
</attribute>
<optional>
<attribute name="macTableManager">
<ref name="macTableManager"/>
</attribute>
</optional>
</define>
<define name="plugdirect">
<attribute name="type">
<value>direct</value>
</attribute>
<attribute name="dev">
<ref name="deviceName"/>
</attribute>
<attribute name="mode">
<choice>
<value>bridge</value>
<value>passthrough</value>
<value>private</value>
<value>vepa</value>
</choice>
</attribute>
</define>
<define name="plughostdevpci">
<attribute name="type">
<value>hostdev-pci</value>
</attribute>
<optional>
<attribute name="managed">
<ref name="virYesNo"/>
</attribute>
</optional>
<optional>
<element name="driver">
<attribute name="name">
<choice>
<value>kvm</value>
<value>vfio</value>
</choice>
</attribute>
<empty/>
</element>
</optional>
<element name='address'>
<ref name="pciaddress"/>
</element>
</define>
</grammar>

View File

@ -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

View File

@ -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 = \

View File

@ -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
* <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", "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, "<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");
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;
if (def->bandwidth)
virNetDevBandwidthFormat(def->bandwidth, def->class_id, buf);
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_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, "<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;
}

View File

@ -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
* <http://www.gnu.org/licenses/>.
*
*/
#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);

View File

@ -1075,6 +1075,16 @@ virNetworkObjUpdate;
virNetworkObjUpdateAssignDef;
# conf/virnetworkportdef.h
virNetworkPortDefFormat;
virNetworkPortDefFormatBuf;
virNetworkPortDefFree;
virNetworkPortDefParseFile;
virNetworkPortDefParseNode;
virNetworkPortDefParseString;
virNetworkPortDefSaveStatus;
# conf/virnodedeviceobj.h
virNodeDeviceObjEndAPI;
virNodeDeviceObjGetDef;

View File

@ -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 \

View File

@ -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>

View File

@ -0,0 +1,15 @@
<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'/>
<bandwidth classID='1729'>
<inbound average='1000' peak='4000' floor='2000' burst='1024'/>
<outbound average='128' peak='256' burst='32768'/>
</bandwidth>
<rxfilters trustGuest='yes'/>
<plug type='bridge' bridge='virbr0'/>
</networkport>

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,15 @@
<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'/>
<bandwidth classID='1729'>
<inbound average='1000' peak='4000' floor='2000' burst='1024'/>
<outbound average='128' peak='256' burst='32768'/>
</bandwidth>
<rxfilters trustGuest='yes'/>
<plug type='network' bridge='virbr0'/>
</networkport>

View File

@ -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>

View File

@ -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)

View File

@ -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");