mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-18 10:35:20 +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>
|
</devices>
|
||||||
...
|
...
|
||||||
|
|
||||||
Userspace SLIRP stack
|
Userspace (SLIRP or passt) connection
|
||||||
^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Provides a virtual LAN with NAT to the outside world. The virtual network has
|
The ``user`` type connects the guest interface to the outside via a
|
||||||
DHCP & DNS services and will give the guest VM addresses starting from
|
transparent userspace proxy that doesn't require any special system
|
||||||
``10.0.2.15``. The default router will be ``10.0.2.2`` and the DNS server will
|
privileges, making it usable in cases when libvirt itself is running
|
||||||
be ``10.0.2.3``. This networking is the only option for unprivileged users who
|
with no privileges (e.g. libvirt's "session mode" daemon, or when
|
||||||
need their VMs to have outgoing access. :since:`Since 3.8.0` it is possible to
|
libvirt is run inside an unprivileged container).
|
||||||
override the default network address by including an ``ip`` element specifying
|
|
||||||
an IPv4 address in its one mandatory attribute, ``address``. Optionally, a
|
By default, this user proxy is done with QEMU's internal SLIRP driver
|
||||||
second ``ip`` element with a ``family`` attribute set to "ipv6" can be specified
|
which has DHCP & DNS services that give the guest IP addresses
|
||||||
to add an IPv6 address to the interface. ``address``. Optionally, address
|
starting from ``10.0.2.15``, a default route of ``10.0.2.2`` and DNS
|
||||||
``prefix`` can be specified.
|
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>
|
</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
|
Generic ethernet connection
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
@ -632,6 +632,19 @@ VIR_ENUM_IMPL(virDomainNetInterfaceLinkState,
|
|||||||
"down",
|
"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_ENUM_IMPL(virDomainChrDeviceState,
|
||||||
VIR_DOMAIN_CHR_DEVICE_STATE_LAST,
|
VIR_DOMAIN_CHR_DEVICE_STATE_LAST,
|
||||||
"default",
|
"default",
|
||||||
@ -2611,10 +2624,26 @@ virDomainNetTeamingInfoFree(virDomainNetTeamingInfo *teaming)
|
|||||||
g_free(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
|
void
|
||||||
virDomainNetDefFree(virDomainNetDef *def)
|
virDomainNetDefFree(virDomainNetDef *def)
|
||||||
{
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
if (!def)
|
if (!def)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -2672,6 +2701,8 @@ virDomainNetDefFree(virDomainNetDef *def)
|
|||||||
|
|
||||||
g_free(def->backend.tap);
|
g_free(def->backend.tap);
|
||||||
g_free(def->backend.vhost);
|
g_free(def->backend.vhost);
|
||||||
|
g_free(def->backend.logFile);
|
||||||
|
g_free(def->backend.upstream);
|
||||||
virDomainNetTeamingInfoFree(def->teaming);
|
virDomainNetTeamingInfoFree(def->teaming);
|
||||||
g_free(def->virtPortProfile);
|
g_free(def->virtPortProfile);
|
||||||
g_free(def->script);
|
g_free(def->script);
|
||||||
@ -2693,6 +2724,10 @@ virDomainNetDefFree(virDomainNetDef *def)
|
|||||||
virNetDevBandwidthFree(def->bandwidth);
|
virNetDevBandwidthFree(def->bandwidth);
|
||||||
virNetDevVlanClear(&def->vlan);
|
virNetDevVlanClear(&def->vlan);
|
||||||
|
|
||||||
|
for (i = 0; i < def->nPortForwards; i++)
|
||||||
|
virDomainNetPortForwardFree(def->portForwards[i]);
|
||||||
|
g_free(def->portForwards);
|
||||||
|
|
||||||
virObjectUnref(def->privateData);
|
virObjectUnref(def->privateData);
|
||||||
g_free(def);
|
g_free(def);
|
||||||
}
|
}
|
||||||
@ -8995,6 +9030,14 @@ virDomainNetBackendParseXML(xmlNodePtr node,
|
|||||||
g_autofree char *tap = virXMLPropString(node, "tap");
|
g_autofree char *tap = virXMLPropString(node, "tap");
|
||||||
g_autofree char *vhost = virXMLPropString(node, "vhost");
|
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)
|
if (tap)
|
||||||
def->backend.tap = virFileSanitizePath(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
|
static int
|
||||||
virDomainNetDefParseXMLRequireSource(virDomainNetDef *def,
|
virDomainNetDefParseXMLRequireSource(virDomainNetDef *def,
|
||||||
xmlNodePtr source_node)
|
xmlNodePtr source_node)
|
||||||
@ -9398,6 +9555,9 @@ virDomainNetDefParseXML(virDomainXMLOption *xmlopt,
|
|||||||
ctxt, &def->guestIP) < 0)
|
ctxt, &def->guestIP) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (virDomainNetPortForwardsParseXML(def, ctxt) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (def->managed_tap != VIR_TRISTATE_BOOL_NO && def->ifname &&
|
if (def->managed_tap != VIR_TRISTATE_BOOL_NO && def->ifname &&
|
||||||
(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
|
(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
|
||||||
(STRPREFIX(def->ifname, VIR_NET_GENERATED_VNET_PREFIX) ||
|
(STRPREFIX(def->ifname, VIR_NET_GENERATED_VNET_PREFIX) ||
|
||||||
@ -23316,14 +23476,78 @@ static void
|
|||||||
virDomainNetBackendFormat(virBuffer *buf,
|
virDomainNetBackendFormat(virBuffer *buf,
|
||||||
virDomainNetBackend *backend)
|
virDomainNetBackend *backend)
|
||||||
{
|
{
|
||||||
|
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
|
||||||
|
|
||||||
if (!(backend->tap || backend->vhost))
|
if (backend->type) {
|
||||||
return;
|
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);
|
static void
|
||||||
virBufferEscapeString(buf, " vhost='%s'", backend->vhost);
|
virDomainNetPortForwardRangesFormat(virBuffer *buf,
|
||||||
virBufferAddLit(buf, "/>\n");
|
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)
|
if (virDomainNetIPInfoFormat(buf, &def->guestIP) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (virDomainNetPortForwardsFormat(buf, def) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
virBufferEscapeString(buf, "<script path='%s'/>\n",
|
virBufferEscapeString(buf, "<script path='%s'/>\n",
|
||||||
def->script);
|
def->script);
|
||||||
virBufferEscapeString(buf, "<downscript path='%s'/>\n",
|
virBufferEscapeString(buf, "<downscript path='%s'/>\n",
|
||||||
|
@ -1023,6 +1023,21 @@ typedef enum {
|
|||||||
VIR_DOMAIN_NET_INTERFACE_LINK_STATE_LAST
|
VIR_DOMAIN_NET_INTERFACE_LINK_STATE_LAST
|
||||||
} virDomainNetInterfaceLinkState;
|
} 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
|
/* Config that was actually used to bring up interface, after
|
||||||
* resolving network reference. This is private data, only used within
|
* resolving network reference. This is private data, only used within
|
||||||
* libvirt, but still must maintain backward compatibility, because
|
* libvirt, but still must maintain backward compatibility, because
|
||||||
@ -1052,8 +1067,27 @@ struct _virDomainActualNetDef {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct _virDomainNetBackend {
|
struct _virDomainNetBackend {
|
||||||
|
virDomainNetBackendType type;
|
||||||
char *tap;
|
char *tap;
|
||||||
char *vhost;
|
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 */
|
/* Stores the virtual network interface configuration */
|
||||||
@ -1159,6 +1193,8 @@ struct _virDomainNetDef {
|
|||||||
char *ifname_guest_actual;
|
char *ifname_guest_actual;
|
||||||
char *ifname_guest;
|
char *ifname_guest;
|
||||||
virNetDevIPInfo guestIP;
|
virNetDevIPInfo guestIP;
|
||||||
|
size_t nPortForwards;
|
||||||
|
virDomainNetPortForward **portForwards;
|
||||||
virDomainDeviceInfo info;
|
virDomainDeviceInfo info;
|
||||||
char *filter;
|
char *filter;
|
||||||
GHashTable *filterparams;
|
GHashTable *filterparams;
|
||||||
@ -3470,6 +3506,8 @@ void virDomainVsockDefFree(virDomainVsockDef *vsock);
|
|||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainVsockDef, virDomainVsockDefFree);
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainVsockDef, virDomainVsockDefFree);
|
||||||
void virDomainNetTeamingInfoFree(virDomainNetTeamingInfo *teaming);
|
void virDomainNetTeamingInfoFree(virDomainNetTeamingInfo *teaming);
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetTeamingInfo, virDomainNetTeamingInfoFree);
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetTeamingInfo, virDomainNetTeamingInfoFree);
|
||||||
|
void virDomainNetPortForwardFree(virDomainNetPortForward *pf);
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetPortForward, virDomainNetPortForwardFree);
|
||||||
void virDomainNetDefFree(virDomainNetDef *def);
|
void virDomainNetDefFree(virDomainNetDef *def);
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetDef, virDomainNetDefFree);
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetDef, virDomainNetDefFree);
|
||||||
void virDomainSmartcardDefFree(virDomainSmartcardDef *def);
|
void virDomainSmartcardDefFree(virDomainSmartcardDef *def);
|
||||||
@ -4058,6 +4096,8 @@ VIR_ENUM_DECL(virDomainNetVirtioTxMode);
|
|||||||
VIR_ENUM_DECL(virDomainNetMacType);
|
VIR_ENUM_DECL(virDomainNetMacType);
|
||||||
VIR_ENUM_DECL(virDomainNetTeaming);
|
VIR_ENUM_DECL(virDomainNetTeaming);
|
||||||
VIR_ENUM_DECL(virDomainNetInterfaceLinkState);
|
VIR_ENUM_DECL(virDomainNetInterfaceLinkState);
|
||||||
|
VIR_ENUM_DECL(virDomainNetBackend);
|
||||||
|
VIR_ENUM_DECL(virDomainNetProto);
|
||||||
VIR_ENUM_DECL(virDomainNetModel);
|
VIR_ENUM_DECL(virDomainNetModel);
|
||||||
VIR_ENUM_DECL(virDomainChrDevice);
|
VIR_ENUM_DECL(virDomainChrDevice);
|
||||||
VIR_ENUM_DECL(virDomainChrChannelTarget);
|
VIR_ENUM_DECL(virDomainChrChannelTarget);
|
||||||
|
@ -2134,6 +2134,14 @@ virDomainNetDefValidate(const virDomainNetDef *net)
|
|||||||
return -1;
|
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) {
|
switch (net->type) {
|
||||||
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
|
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
|
||||||
if (!virDomainNetIsVirtioModel(net)) {
|
if (!virDomainNetIsVirtioModel(net)) {
|
||||||
@ -2150,6 +2158,29 @@ virDomainNetDefValidate(const virDomainNetDef *net)
|
|||||||
}
|
}
|
||||||
break;
|
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_NETWORK:
|
||||||
case VIR_DOMAIN_NET_TYPE_VDPA:
|
case VIR_DOMAIN_NET_TYPE_VDPA:
|
||||||
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
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_HOSTDEV:
|
||||||
case VIR_DOMAIN_NET_TYPE_VDS:
|
case VIR_DOMAIN_NET_TYPE_VDS:
|
||||||
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
||||||
case VIR_DOMAIN_NET_TYPE_USER:
|
|
||||||
case VIR_DOMAIN_NET_TYPE_NULL:
|
case VIR_DOMAIN_NET_TYPE_NULL:
|
||||||
case VIR_DOMAIN_NET_TYPE_LAST:
|
case VIR_DOMAIN_NET_TYPE_LAST:
|
||||||
break;
|
break;
|
||||||
|
@ -174,6 +174,10 @@ typedef struct _virDomainNVRAMDef virDomainNVRAMDef;
|
|||||||
|
|
||||||
typedef struct _virDomainNetBackend virDomainNetBackend;
|
typedef struct _virDomainNetBackend virDomainNetBackend;
|
||||||
|
|
||||||
|
typedef struct _virDomainNetPortForwardRange virDomainNetPortForwardRange;
|
||||||
|
|
||||||
|
typedef struct _virDomainNetPortForward virDomainNetPortForward;
|
||||||
|
|
||||||
typedef struct _virDomainNetDef virDomainNetDef;
|
typedef struct _virDomainNetDef virDomainNetDef;
|
||||||
|
|
||||||
typedef struct _virDomainNetTeamingInfo virDomainNetTeamingInfo;
|
typedef struct _virDomainNetTeamingInfo virDomainNetTeamingInfo;
|
||||||
|
@ -551,6 +551,7 @@ virDomainNetIsVirtioModel;
|
|||||||
virDomainNetModelTypeFromString;
|
virDomainNetModelTypeFromString;
|
||||||
virDomainNetModelTypeToString;
|
virDomainNetModelTypeToString;
|
||||||
virDomainNetNotifyActualDevice;
|
virDomainNetNotifyActualDevice;
|
||||||
|
virDomainNetPortForwardFree;
|
||||||
virDomainNetReleaseActualDevice;
|
virDomainNetReleaseActualDevice;
|
||||||
virDomainNetRemove;
|
virDomainNetRemove;
|
||||||
virDomainNetRemoveByObj;
|
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-vhostuser");
|
||||||
DO_TEST_NOCAPS("net-user");
|
DO_TEST_NOCAPS("net-user");
|
||||||
DO_TEST_NOCAPS("net-user-addr");
|
DO_TEST_NOCAPS("net-user-addr");
|
||||||
|
DO_TEST_NOCAPS("net-user-passt");
|
||||||
DO_TEST_NOCAPS("net-virtio");
|
DO_TEST_NOCAPS("net-virtio");
|
||||||
DO_TEST_NOCAPS("net-virtio-device");
|
DO_TEST_NOCAPS("net-virtio-device");
|
||||||
DO_TEST_NOCAPS("net-virtio-disable-offloads");
|
DO_TEST_NOCAPS("net-virtio-disable-offloads");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user