mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-30 16:35:24 +00:00
conf: parse/format passt-related XML additions
This implements XML config to represent a subset of the features supported by 'passt' (https://passt.top), which is an alternative backend for emulated network devices that requires no elevated privileges (similar to slirp, but "better"). Along with setting the backend to use passt (via <backend type='passt'/> when the interface type='user'), we also support passt's --log-file and --interface options (via the <backend> subelement logFile and upstream attributes) and its --tcp-ports and --udp-ports options (which selectively forward incoming connections to the host on to the guest) via the new <portForward> subelement of <interface>. Here is an example of the config for a network interface that uses passt to connect: <interface type='user'> <mac address='52:54:00:a8:33:fc'/> <ip address='192.168.221.122' family='ipv4'/> <model type='virtio'/> <backend type='passt' logFile='/tmp/xyzzy.log' upstream='eth0'/> <portForward address='10.0.0.1' proto='tcp' dev='eth0'> <range start='2022' to='22'/> <range start='5000' end='5099' to='1000'/> <range start='5010' end='5029' exclude='yes'/> </portForward> <portForward proto='udp'> <range start='10101'/> </portForward> </interface> In this case: * the guest will be offered address 192.168.221.122 for its interface via DHCP * the passt process will write all log messages to /tmp/xyzzy.log * routes to the outside for the guest will be derived from the addresses and routes associated with the host interface "eth0". * incoming tcp port 2022 to the host will be forwarded to port 22 on the guest. * incoming tcp ports 5000-5099 (with the exception of ports 5010-5029) to the host will be forwarded to port 1000-1099 on the guest. * incoming udp packets on port 10101 will be forwarded (unchanged) to the guest. Signed-off-by: Laine Stump <laine@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
parent
63fbe529fc
commit
a8ee7ae301
@ -4775,19 +4775,25 @@ to the interface.
|
||||
</devices>
|
||||
...
|
||||
|
||||
Userspace SLIRP stack
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
Userspace (SLIRP or passt) connection
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Provides a virtual LAN with NAT to the outside world. The virtual network has
|
||||
DHCP & DNS services and will give the guest VM addresses starting from
|
||||
``10.0.2.15``. The default router will be ``10.0.2.2`` and the DNS server will
|
||||
be ``10.0.2.3``. This networking is the only option for unprivileged users who
|
||||
need their VMs to have outgoing access. :since:`Since 3.8.0` it is possible to
|
||||
override the default network address by including an ``ip`` element specifying
|
||||
an IPv4 address in its one mandatory attribute, ``address``. Optionally, a
|
||||
second ``ip`` element with a ``family`` attribute set to "ipv6" can be specified
|
||||
to add an IPv6 address to the interface. ``address``. Optionally, address
|
||||
``prefix`` can be specified.
|
||||
The ``user`` type connects the guest interface to the outside via a
|
||||
transparent userspace proxy that doesn't require any special system
|
||||
privileges, making it usable in cases when libvirt itself is running
|
||||
with no privileges (e.g. libvirt's "session mode" daemon, or when
|
||||
libvirt is run inside an unprivileged container).
|
||||
|
||||
By default, this user proxy is done with QEMU's internal SLIRP driver
|
||||
which has DHCP & DNS services that give the guest IP addresses
|
||||
starting from ``10.0.2.15``, a default route of ``10.0.2.2`` and DNS
|
||||
server of ``10.0.2.3``. :since:`Since 3.8.0` it is possible to override
|
||||
the default network address by including an ``ip`` element specifying
|
||||
an IPv4 address in its one mandatory attribute,
|
||||
``address``. Optionally, a second ``ip`` element with a ``family``
|
||||
attribute set to "ipv6" can be specified to add an IPv6 address to the
|
||||
interface. ``address``. Optionally, address ``prefix`` can be
|
||||
specified.
|
||||
|
||||
::
|
||||
|
||||
@ -4803,6 +4809,71 @@ to add an IPv6 address to the interface. ``address``. Optionally, address
|
||||
</devices>
|
||||
...
|
||||
|
||||
:since:`Since 9.0.0` an alternate backend implementation of the
|
||||
``user`` interface type can be selected by setting the interface's
|
||||
``<backend>`` subelement ``type`` attribute to ``passt``. In this
|
||||
case, the passt transport (https://passt.top) is used. Similar to
|
||||
SLIRP, passt has an internal DHCP server that provides a requesting
|
||||
guest with one ipv4 and one ipv6 address; it then uses userspace
|
||||
proxies and a separate network namespace to provide outgoing
|
||||
UDP/TCP/ICMP sessions, and optionally redirect incoming traffic
|
||||
destined for the host toward the guest instead.
|
||||
|
||||
When the passt backend is used, the ``<backend>`` attribute
|
||||
``logFile`` can be used to tell the passt process for this interface
|
||||
where to write its message log, and the ``<backend>`` attribute
|
||||
``upstream`` can tell it to restrict upstream traffic to a particular
|
||||
host interface.
|
||||
|
||||
Additionally, when passt is used, multiple ``<portForward>`` elements
|
||||
can be added to forward incoming network traffic for the host to this
|
||||
guest interface. Each ``<portForward>`` must have a ``proto``
|
||||
attribute (set to ``tcp`` or ``udp``) and optional original
|
||||
``address`` (if not specified, then all incoming sessions to any host
|
||||
IP for the given proto/port(s) will be forwarded to the guest).
|
||||
|
||||
The decision of which ports to forward is described with zero or more
|
||||
``<range>`` subelements of ``<portForward>`` (if there is no
|
||||
``<range>`` then **all** ports for the given proto/address will be
|
||||
forwarded). Each ``<range>`` has a ``start`` and optional ``end``
|
||||
attribute. If ``end`` is omitted then a single port will be forwarded,
|
||||
otherwise all ports between ``start`` and ``end`` (inclusive) will be
|
||||
forwarded. If the port number(s) should remain unmodified as the
|
||||
session is forwarded, no further options are needed, but if the guest
|
||||
is expecting the sessions on a different port, then this should be
|
||||
specified with the ``to`` attribute of ``<range>`` - the port number
|
||||
of each forwarded session in the range will be offeset by "``to`` -
|
||||
``start``". A ``<range>`` element can also be used to specify a range
|
||||
of ports that should **not** be forwarded. This is done by setting the
|
||||
range's ``exclude`` attribute to ``yes``. This may not seem very
|
||||
useful, but can be when it is desirable to forward a long range of
|
||||
ports **with the exception of some subset**.
|
||||
|
||||
::
|
||||
|
||||
...
|
||||
<devices>
|
||||
...
|
||||
<interface type='user'>
|
||||
<backend type='passt' logFile='/var/log/passt.log' upstream='eth0'/>
|
||||
<mac address="00:11:22:33:44:55"/>
|
||||
<ip family='ipv4' address='172.17.2.0' prefix='24'/>
|
||||
<ip family='ipv6' address='2001:db8:ac10:fd01::' prefix='64'/>
|
||||
<portForward proto='tcp' address='2001:db8:ac10:fd01::1:10' start='2022'>
|
||||
<port start='22'/>
|
||||
</portForward>
|
||||
<portForward proto='udp' address='1.2.3.4' start='5000' end='5020'>
|
||||
<port start='6000' end='6020'/>
|
||||
</portForward>
|
||||
<portForward exclude='yes' proto='tcp' address='1.2.3.4' start='5010' end='5015'/>
|
||||
<portForward proto='tcp' start='80'/>
|
||||
<portForward proto='tcp' start='443'>
|
||||
<port start='344'/>
|
||||
</portForward>
|
||||
</interface>
|
||||
</devices>
|
||||
...
|
||||
|
||||
Generic ethernet connection
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -632,6 +632,19 @@ VIR_ENUM_IMPL(virDomainNetInterfaceLinkState,
|
||||
"down",
|
||||
);
|
||||
|
||||
VIR_ENUM_IMPL(virDomainNetBackend,
|
||||
VIR_DOMAIN_NET_BACKEND_LAST,
|
||||
"default",
|
||||
"passt",
|
||||
);
|
||||
|
||||
VIR_ENUM_IMPL(virDomainNetProto,
|
||||
VIR_DOMAIN_NET_PROTO_LAST,
|
||||
"none",
|
||||
"tcp",
|
||||
"udp",
|
||||
);
|
||||
|
||||
VIR_ENUM_IMPL(virDomainChrDeviceState,
|
||||
VIR_DOMAIN_CHR_DEVICE_STATE_LAST,
|
||||
"default",
|
||||
@ -2611,10 +2624,26 @@ virDomainNetTeamingInfoFree(virDomainNetTeamingInfo *teaming)
|
||||
g_free(teaming);
|
||||
}
|
||||
|
||||
void
|
||||
virDomainNetPortForwardFree(virDomainNetPortForward *pf)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (pf)
|
||||
g_free(pf->dev);
|
||||
|
||||
for (i = 0; i < pf->nRanges; i++)
|
||||
g_free(pf->ranges[i]);
|
||||
|
||||
g_free(pf->ranges);
|
||||
g_free(pf);
|
||||
}
|
||||
|
||||
void
|
||||
virDomainNetDefFree(virDomainNetDef *def)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!def)
|
||||
return;
|
||||
|
||||
@ -2672,6 +2701,8 @@ virDomainNetDefFree(virDomainNetDef *def)
|
||||
|
||||
g_free(def->backend.tap);
|
||||
g_free(def->backend.vhost);
|
||||
g_free(def->backend.logFile);
|
||||
g_free(def->backend.upstream);
|
||||
virDomainNetTeamingInfoFree(def->teaming);
|
||||
g_free(def->virtPortProfile);
|
||||
g_free(def->script);
|
||||
@ -2693,6 +2724,10 @@ virDomainNetDefFree(virDomainNetDef *def)
|
||||
virNetDevBandwidthFree(def->bandwidth);
|
||||
virNetDevVlanClear(&def->vlan);
|
||||
|
||||
for (i = 0; i < def->nPortForwards; i++)
|
||||
virDomainNetPortForwardFree(def->portForwards[i]);
|
||||
g_free(def->portForwards);
|
||||
|
||||
virObjectUnref(def->privateData);
|
||||
g_free(def);
|
||||
}
|
||||
@ -8995,6 +9030,14 @@ virDomainNetBackendParseXML(xmlNodePtr node,
|
||||
g_autofree char *tap = virXMLPropString(node, "tap");
|
||||
g_autofree char *vhost = virXMLPropString(node, "vhost");
|
||||
|
||||
if (virXMLPropEnum(node, "type", virDomainNetBackendTypeFromString,
|
||||
VIR_XML_PROP_NONZERO, &def->backend.type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
def->backend.logFile = virXMLPropString(node, "logFile");
|
||||
def->backend.upstream = virXMLPropString(node, "upstream");
|
||||
|
||||
if (tap)
|
||||
def->backend.tap = virFileSanitizePath(tap);
|
||||
|
||||
@ -9008,6 +9051,120 @@ virDomainNetBackendParseXML(xmlNodePtr node,
|
||||
}
|
||||
|
||||
|
||||
static virDomainNetPortForwardRange *
|
||||
virDomainNetPortForwardRangeParseXML(xmlNodePtr node,
|
||||
xmlXPathContextPtr ctxt)
|
||||
{
|
||||
VIR_XPATH_NODE_AUTORESTORE(ctxt)
|
||||
g_autofree virDomainNetPortForwardRange *def = g_new0(virDomainNetPortForwardRange, 1);
|
||||
|
||||
ctxt->node = node;
|
||||
|
||||
if (virXMLPropUInt(node, "start", 10,
|
||||
VIR_XML_PROP_NONZERO, &def->start) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (virXMLPropUInt(node, "end", 10,
|
||||
VIR_XML_PROP_NONZERO, &def->end) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (virXMLPropUInt(node, "to", 10,
|
||||
VIR_XML_PROP_NONZERO, &def->to) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (virXMLPropTristateBool(node, "exclude", VIR_XML_PROP_NONE,
|
||||
&def->exclude) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_steal_pointer(&def);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virDomainNetPortForwardRangesParseXML(virDomainNetPortForward *def,
|
||||
xmlXPathContextPtr ctxt)
|
||||
{
|
||||
int nRanges;
|
||||
g_autofree xmlNodePtr *ranges = NULL;
|
||||
size_t i;
|
||||
|
||||
if ((nRanges = virXPathNodeSet("./range", ctxt, &ranges)) <= 0)
|
||||
return nRanges;
|
||||
|
||||
def->ranges = g_new0(virDomainNetPortForwardRange *, nRanges);
|
||||
|
||||
for (i = 0; i < nRanges; i++) {
|
||||
g_autofree virDomainNetPortForwardRange *range = NULL;
|
||||
|
||||
if (!(range = virDomainNetPortForwardRangeParseXML(ranges[i], ctxt)))
|
||||
return -1;
|
||||
|
||||
def->ranges[def->nRanges++] = g_steal_pointer(&range);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static virDomainNetPortForward *
|
||||
virDomainNetPortForwardDefParseXML(xmlNodePtr node,
|
||||
xmlXPathContextPtr ctxt)
|
||||
{
|
||||
VIR_XPATH_NODE_AUTORESTORE(ctxt)
|
||||
g_autofree char *address = NULL;
|
||||
g_autoptr(virDomainNetPortForward) def = g_new0(virDomainNetPortForward, 1);
|
||||
|
||||
ctxt->node = node;
|
||||
|
||||
if (virXMLPropEnum(node, "proto", virDomainNetProtoTypeFromString,
|
||||
VIR_XML_PROP_REQUIRED | VIR_XML_PROP_NONZERO,
|
||||
&def->proto) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
address = virXMLPropString(node, "address");
|
||||
if (address && virSocketAddrParse(&def->address, address, AF_UNSPEC) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("Invalid address '%s' in <portForward>"), address);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
def->dev = virXMLPropString(node, "dev");
|
||||
|
||||
if (virDomainNetPortForwardRangesParseXML(def, ctxt) < 0)
|
||||
return NULL;
|
||||
|
||||
return g_steal_pointer(&def);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virDomainNetPortForwardsParseXML(virDomainNetDef *def,
|
||||
xmlXPathContextPtr ctxt)
|
||||
{
|
||||
int nPortForwards;
|
||||
g_autofree xmlNodePtr *portForwards = NULL;
|
||||
size_t i;
|
||||
|
||||
if ((nPortForwards = virXPathNodeSet("./portForward",
|
||||
ctxt, &portForwards)) <= 0) {
|
||||
return nPortForwards;
|
||||
}
|
||||
|
||||
def->portForwards = g_new0(virDomainNetPortForward *, nPortForwards);
|
||||
|
||||
for (i = 0; i < nPortForwards; i++) {
|
||||
g_autoptr(virDomainNetPortForward) pf = NULL;
|
||||
|
||||
if (!(pf = virDomainNetPortForwardDefParseXML(portForwards[i], ctxt)))
|
||||
return -1;
|
||||
|
||||
def->portForwards[def->nPortForwards++] = g_steal_pointer(&pf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virDomainNetDefParseXMLRequireSource(virDomainNetDef *def,
|
||||
xmlNodePtr source_node)
|
||||
@ -9398,6 +9555,9 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt,
|
||||
ctxt, &def->guestIP) < 0)
|
||||
return NULL;
|
||||
|
||||
if (virDomainNetPortForwardsParseXML(def, ctxt) < 0)
|
||||
return NULL;
|
||||
|
||||
if (def->managed_tap != VIR_TRISTATE_BOOL_NO && def->ifname &&
|
||||
(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
|
||||
(STRPREFIX(def->ifname, VIR_NET_GENERATED_VNET_PREFIX) ||
|
||||
@ -23316,14 +23476,78 @@ static void
|
||||
virDomainNetBackendFormat(virBuffer *buf,
|
||||
virDomainNetBackend *backend)
|
||||
{
|
||||
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
|
||||
|
||||
if (!(backend->tap || backend->vhost))
|
||||
return;
|
||||
if (backend->type) {
|
||||
virBufferAsprintf(&attrBuf, " type='%s'",
|
||||
virDomainNetBackendTypeToString(backend->type));
|
||||
}
|
||||
virBufferEscapeString(&attrBuf, " tap='%s'", backend->tap);
|
||||
virBufferEscapeString(&attrBuf, " vhost='%s'", backend->vhost);
|
||||
virBufferEscapeString(&attrBuf, " logFile='%s'", backend->logFile);
|
||||
virBufferEscapeString(&attrBuf, " upstream='%s'", backend->upstream);
|
||||
virXMLFormatElement(buf, "backend", &attrBuf, NULL);
|
||||
}
|
||||
|
||||
virBufferAddLit(buf, "<backend");
|
||||
virBufferEscapeString(buf, " tap='%s'", backend->tap);
|
||||
virBufferEscapeString(buf, " vhost='%s'", backend->vhost);
|
||||
virBufferAddLit(buf, "/>\n");
|
||||
|
||||
static void
|
||||
virDomainNetPortForwardRangesFormat(virBuffer *buf,
|
||||
virDomainNetPortForward *def)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < def->nRanges; i++) {
|
||||
virDomainNetPortForwardRange *range = def->ranges[i];
|
||||
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
|
||||
|
||||
if (range->start) {
|
||||
virBufferAsprintf(&attrBuf, " start='%u'", range->start);
|
||||
if (range->end)
|
||||
virBufferAsprintf(&attrBuf, " end='%u'", range->end);
|
||||
if (range->to)
|
||||
virBufferAsprintf(&attrBuf, " to='%u'", range->to);
|
||||
}
|
||||
|
||||
if (range->exclude) {
|
||||
virBufferAsprintf(&attrBuf, " exclude='%s'",
|
||||
virTristateBoolTypeToString(range->exclude));
|
||||
}
|
||||
virXMLFormatElement(buf, "range", &attrBuf, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virDomainNetPortForwardsFormat(virBuffer *buf,
|
||||
virDomainNetDef *def)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!def->nPortForwards)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < def->nPortForwards; i++) {
|
||||
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
|
||||
g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
|
||||
virDomainNetPortForward *pf = def->portForwards[i];
|
||||
|
||||
virBufferAsprintf(&attrBuf, " proto='%s'",
|
||||
virDomainNetProtoTypeToString(pf->proto));
|
||||
if (VIR_SOCKET_ADDR_VALID(&pf->address)) {
|
||||
g_autofree char *ipStr = virSocketAddrFormat(&pf->address);
|
||||
|
||||
if (!ipStr)
|
||||
return -1;
|
||||
|
||||
virBufferAsprintf(&attrBuf, " address='%s'", ipStr);
|
||||
}
|
||||
virBufferEscapeString(&attrBuf, " dev='%s'", pf->dev);
|
||||
|
||||
virDomainNetPortForwardRangesFormat(&childBuf, pf);
|
||||
virXMLFormatElementEmpty(buf, "portForward", &attrBuf, &childBuf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -23575,6 +23799,9 @@ virDomainNetDefFormat(virBuffer *buf,
|
||||
if (virDomainNetIPInfoFormat(buf, &def->guestIP) < 0)
|
||||
return -1;
|
||||
|
||||
if (virDomainNetPortForwardsFormat(buf, def) < 0)
|
||||
return -1;
|
||||
|
||||
virBufferEscapeString(buf, "<script path='%s'/>\n",
|
||||
def->script);
|
||||
virBufferEscapeString(buf, "<downscript path='%s'/>\n",
|
||||
|
@ -1023,6 +1023,21 @@ typedef enum {
|
||||
VIR_DOMAIN_NET_INTERFACE_LINK_STATE_LAST
|
||||
} virDomainNetInterfaceLinkState;
|
||||
|
||||
typedef enum {
|
||||
VIR_DOMAIN_NET_BACKEND_DEFAULT = 0,
|
||||
VIR_DOMAIN_NET_BACKEND_PASST,
|
||||
|
||||
VIR_DOMAIN_NET_BACKEND_LAST
|
||||
} virDomainNetBackendType;
|
||||
|
||||
typedef enum {
|
||||
VIR_DOMAIN_NET_PROTO_NONE = 0,
|
||||
VIR_DOMAIN_NET_PROTO_TCP,
|
||||
VIR_DOMAIN_NET_PROTO_UDP,
|
||||
|
||||
VIR_DOMAIN_NET_PROTO_LAST
|
||||
} virDomainNetProto;
|
||||
|
||||
/* Config that was actually used to bring up interface, after
|
||||
* resolving network reference. This is private data, only used within
|
||||
* libvirt, but still must maintain backward compatibility, because
|
||||
@ -1052,8 +1067,27 @@ struct _virDomainActualNetDef {
|
||||
};
|
||||
|
||||
struct _virDomainNetBackend {
|
||||
virDomainNetBackendType type;
|
||||
char *tap;
|
||||
char *vhost;
|
||||
/* The following are currently only valid/used when backend type='passt' */
|
||||
char *logFile; /* path to logfile used by passt process */
|
||||
char *upstream; /* host interface to use for traffic egress */
|
||||
};
|
||||
|
||||
struct _virDomainNetPortForwardRange {
|
||||
unsigned int start; /* original dst port range start */
|
||||
unsigned int end; /* range end (0 for "single port") */
|
||||
unsigned int to; /* start of range to forward to (0 for "unchanged") */
|
||||
virTristateBool exclude; /* true if this is a range to *not* forward */
|
||||
};
|
||||
|
||||
struct _virDomainNetPortForward {
|
||||
char *dev; /* host interface of incoming traffic */
|
||||
virDomainNetProto proto; /* tcp/udp */
|
||||
virSocketAddr address; /* original dst address (empty = wildcard) */
|
||||
size_t nRanges;
|
||||
virDomainNetPortForwardRange **ranges; /* list of ranges to forward */
|
||||
};
|
||||
|
||||
/* Stores the virtual network interface configuration */
|
||||
@ -1159,6 +1193,8 @@ struct _virDomainNetDef {
|
||||
char *ifname_guest_actual;
|
||||
char *ifname_guest;
|
||||
virNetDevIPInfo guestIP;
|
||||
size_t nPortForwards;
|
||||
virDomainNetPortForward **portForwards;
|
||||
virDomainDeviceInfo info;
|
||||
char *filter;
|
||||
GHashTable *filterparams;
|
||||
@ -3470,6 +3506,8 @@ void virDomainVsockDefFree(virDomainVsockDef *vsock);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainVsockDef, virDomainVsockDefFree);
|
||||
void virDomainNetTeamingInfoFree(virDomainNetTeamingInfo *teaming);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetTeamingInfo, virDomainNetTeamingInfoFree);
|
||||
void virDomainNetPortForwardFree(virDomainNetPortForward *pf);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetPortForward, virDomainNetPortForwardFree);
|
||||
void virDomainNetDefFree(virDomainNetDef *def);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetDef, virDomainNetDefFree);
|
||||
void virDomainSmartcardDefFree(virDomainSmartcardDef *def);
|
||||
@ -4058,6 +4096,8 @@ VIR_ENUM_DECL(virDomainNetVirtioTxMode);
|
||||
VIR_ENUM_DECL(virDomainNetMacType);
|
||||
VIR_ENUM_DECL(virDomainNetTeaming);
|
||||
VIR_ENUM_DECL(virDomainNetInterfaceLinkState);
|
||||
VIR_ENUM_DECL(virDomainNetBackend);
|
||||
VIR_ENUM_DECL(virDomainNetProto);
|
||||
VIR_ENUM_DECL(virDomainNetModel);
|
||||
VIR_ENUM_DECL(virDomainChrDevice);
|
||||
VIR_ENUM_DECL(virDomainChrChannelTarget);
|
||||
|
@ -2134,6 +2134,14 @@ virDomainNetDefValidate(const virDomainNetDef *net)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (net->type != VIR_DOMAIN_NET_TYPE_USER) {
|
||||
if (net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("The 'passt' backend can only be used with interface type='user'"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
switch (net->type) {
|
||||
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
|
||||
if (!virDomainNetIsVirtioModel(net)) {
|
||||
@ -2150,6 +2158,29 @@ virDomainNetDefValidate(const virDomainNetDef *net)
|
||||
}
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_NET_TYPE_USER:
|
||||
if (net->backend.type == VIR_DOMAIN_NET_BACKEND_PASST) {
|
||||
size_t p;
|
||||
|
||||
for (p = 0; p < net->nPortForwards; p++) {
|
||||
size_t r;
|
||||
virDomainNetPortForward *pf = net->portForwards[p];
|
||||
|
||||
for (r = 0; r < pf->nRanges; r++) {
|
||||
virDomainNetPortForwardRange *range = pf->ranges[r];
|
||||
|
||||
if (!range->start
|
||||
&& (range->end || range->to
|
||||
|| range->exclude != VIR_TRISTATE_BOOL_ABSENT)) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("The 'range' of a 'portForward' requires 'start' attribute if 'end', 'to', or 'exclude' is specified"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
||||
case VIR_DOMAIN_NET_TYPE_VDPA:
|
||||
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
||||
@ -2162,7 +2193,6 @@ virDomainNetDefValidate(const virDomainNetDef *net)
|
||||
case VIR_DOMAIN_NET_TYPE_HOSTDEV:
|
||||
case VIR_DOMAIN_NET_TYPE_VDS:
|
||||
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
||||
case VIR_DOMAIN_NET_TYPE_USER:
|
||||
case VIR_DOMAIN_NET_TYPE_NULL:
|
||||
case VIR_DOMAIN_NET_TYPE_LAST:
|
||||
break;
|
||||
|
@ -174,6 +174,10 @@ typedef struct _virDomainNVRAMDef virDomainNVRAMDef;
|
||||
|
||||
typedef struct _virDomainNetBackend virDomainNetBackend;
|
||||
|
||||
typedef struct _virDomainNetPortForwardRange virDomainNetPortForwardRange;
|
||||
|
||||
typedef struct _virDomainNetPortForward virDomainNetPortForward;
|
||||
|
||||
typedef struct _virDomainNetDef virDomainNetDef;
|
||||
|
||||
typedef struct _virDomainNetTeamingInfo virDomainNetTeamingInfo;
|
||||
|
@ -551,6 +551,7 @@ virDomainNetIsVirtioModel;
|
||||
virDomainNetModelTypeFromString;
|
||||
virDomainNetModelTypeToString;
|
||||
virDomainNetNotifyActualDevice;
|
||||
virDomainNetPortForwardFree;
|
||||
virDomainNetReleaseActualDevice;
|
||||
virDomainNetRemove;
|
||||
virDomainNetRemoveByObj;
|
||||
|
1
tests/qemuxml2xmloutdata/net-user-passt.xml
Symbolic link
1
tests/qemuxml2xmloutdata/net-user-passt.xml
Symbolic link
@ -0,0 +1 @@
|
||||
../qemuxml2argvdata/net-user-passt.xml
|
@ -459,6 +459,7 @@ mymain(void)
|
||||
DO_TEST_NOCAPS("net-vhostuser");
|
||||
DO_TEST_NOCAPS("net-user");
|
||||
DO_TEST_NOCAPS("net-user-addr");
|
||||
DO_TEST_NOCAPS("net-user-passt");
|
||||
DO_TEST_NOCAPS("net-virtio");
|
||||
DO_TEST_NOCAPS("net-virtio-device");
|
||||
DO_TEST_NOCAPS("net-virtio-disable-offloads");
|
||||
|
Loading…
x
Reference in New Issue
Block a user